@zooique/memora 0.1.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.
Files changed (239) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -0
  3. package/dist/agent/agent.d.ts +343 -0
  4. package/dist/agent/agent.d.ts.map +1 -0
  5. package/dist/agent/agent.js +893 -0
  6. package/dist/agent/agent.js.map +1 -0
  7. package/dist/agent/assembler.d.ts +77 -0
  8. package/dist/agent/assembler.d.ts.map +1 -0
  9. package/dist/agent/assembler.js +115 -0
  10. package/dist/agent/assembler.js.map +1 -0
  11. package/dist/agent/builtinToolHandlers.d.ts +96 -0
  12. package/dist/agent/builtinToolHandlers.d.ts.map +1 -0
  13. package/dist/agent/builtinToolHandlers.js +388 -0
  14. package/dist/agent/builtinToolHandlers.js.map +1 -0
  15. package/dist/agent/builtinTools.d.ts +35 -0
  16. package/dist/agent/builtinTools.d.ts.map +1 -0
  17. package/dist/agent/builtinTools.js +75 -0
  18. package/dist/agent/builtinTools.js.map +1 -0
  19. package/dist/agent/constants.d.ts +67 -0
  20. package/dist/agent/constants.d.ts.map +1 -0
  21. package/dist/agent/constants.js +67 -0
  22. package/dist/agent/constants.js.map +1 -0
  23. package/dist/agent/contextManager.d.ts +130 -0
  24. package/dist/agent/contextManager.d.ts.map +1 -0
  25. package/dist/agent/contextManager.js +287 -0
  26. package/dist/agent/contextManager.js.map +1 -0
  27. package/dist/agent/loop.d.ts +288 -0
  28. package/dist/agent/loop.d.ts.map +1 -0
  29. package/dist/agent/loop.js +756 -0
  30. package/dist/agent/loop.js.map +1 -0
  31. package/dist/agent/managers/autoConfigRefiner.d.ts +39 -0
  32. package/dist/agent/managers/autoConfigRefiner.d.ts.map +1 -0
  33. package/dist/agent/managers/autoConfigRefiner.js +150 -0
  34. package/dist/agent/managers/autoConfigRefiner.js.map +1 -0
  35. package/dist/agent/managers/configManager.d.ts +114 -0
  36. package/dist/agent/managers/configManager.d.ts.map +1 -0
  37. package/dist/agent/managers/configManager.js +186 -0
  38. package/dist/agent/managers/configManager.js.map +1 -0
  39. package/dist/agent/managers/insightExtractor.d.ts +141 -0
  40. package/dist/agent/managers/insightExtractor.d.ts.map +1 -0
  41. package/dist/agent/managers/insightExtractor.js +420 -0
  42. package/dist/agent/managers/insightExtractor.js.map +1 -0
  43. package/dist/agent/managers/memoryAdvisor.d.ts +96 -0
  44. package/dist/agent/managers/memoryAdvisor.d.ts.map +1 -0
  45. package/dist/agent/managers/memoryAdvisor.js +198 -0
  46. package/dist/agent/managers/memoryAdvisor.js.map +1 -0
  47. package/dist/agent/managers/memoryInspector.d.ts +231 -0
  48. package/dist/agent/managers/memoryInspector.d.ts.map +1 -0
  49. package/dist/agent/managers/memoryInspector.js +327 -0
  50. package/dist/agent/managers/memoryInspector.js.map +1 -0
  51. package/dist/agent/managers/sessionManager.d.ts +89 -0
  52. package/dist/agent/managers/sessionManager.d.ts.map +1 -0
  53. package/dist/agent/managers/sessionManager.js +178 -0
  54. package/dist/agent/managers/sessionManager.js.map +1 -0
  55. package/dist/agent/managers/userFactExtractor.d.ts +25 -0
  56. package/dist/agent/managers/userFactExtractor.d.ts.map +1 -0
  57. package/dist/agent/managers/userFactExtractor.js +81 -0
  58. package/dist/agent/managers/userFactExtractor.js.map +1 -0
  59. package/dist/agent/managers/workProjection.d.ts +117 -0
  60. package/dist/agent/managers/workProjection.d.ts.map +1 -0
  61. package/dist/agent/managers/workProjection.js +290 -0
  62. package/dist/agent/managers/workProjection.js.map +1 -0
  63. package/dist/agent/messageHistory.d.ts +157 -0
  64. package/dist/agent/messageHistory.d.ts.map +1 -0
  65. package/dist/agent/messageHistory.js +288 -0
  66. package/dist/agent/messageHistory.js.map +1 -0
  67. package/dist/agent/toolExecutor.d.ts +137 -0
  68. package/dist/agent/toolExecutor.d.ts.map +1 -0
  69. package/dist/agent/toolExecutor.js +209 -0
  70. package/dist/agent/toolExecutor.js.map +1 -0
  71. package/dist/agent/tracer.d.ts +122 -0
  72. package/dist/agent/tracer.d.ts.map +1 -0
  73. package/dist/agent/tracer.js +64 -0
  74. package/dist/agent/tracer.js.map +1 -0
  75. package/dist/agent/types.d.ts +98 -0
  76. package/dist/agent/types.d.ts.map +1 -0
  77. package/dist/agent/types.js +19 -0
  78. package/dist/agent/types.js.map +1 -0
  79. package/dist/config/loader.d.ts +229 -0
  80. package/dist/config/loader.d.ts.map +1 -0
  81. package/dist/config/loader.js +194 -0
  82. package/dist/config/loader.js.map +1 -0
  83. package/dist/eval/evalTypes.d.ts +118 -0
  84. package/dist/eval/evalTypes.d.ts.map +1 -0
  85. package/dist/eval/evalTypes.js +102 -0
  86. package/dist/eval/evalTypes.js.map +1 -0
  87. package/dist/index.d.ts +61 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.js +44 -0
  90. package/dist/index.js.map +1 -0
  91. package/dist/llm/embedding.d.ts +62 -0
  92. package/dist/llm/embedding.d.ts.map +1 -0
  93. package/dist/llm/embedding.js +162 -0
  94. package/dist/llm/embedding.js.map +1 -0
  95. package/dist/llm/factory.d.ts +39 -0
  96. package/dist/llm/factory.d.ts.map +1 -0
  97. package/dist/llm/factory.js +108 -0
  98. package/dist/llm/factory.js.map +1 -0
  99. package/dist/llm/openaiCompatible.d.ts +63 -0
  100. package/dist/llm/openaiCompatible.d.ts.map +1 -0
  101. package/dist/llm/openaiCompatible.js +340 -0
  102. package/dist/llm/openaiCompatible.js.map +1 -0
  103. package/dist/llm/provider.d.ts +91 -0
  104. package/dist/llm/provider.d.ts.map +1 -0
  105. package/dist/llm/provider.js +14 -0
  106. package/dist/llm/provider.js.map +1 -0
  107. package/dist/llm/types.d.ts +25 -0
  108. package/dist/llm/types.d.ts.map +1 -0
  109. package/dist/llm/types.js +7 -0
  110. package/dist/llm/types.js.map +1 -0
  111. package/dist/logging/logger.d.ts +39 -0
  112. package/dist/logging/logger.d.ts.map +1 -0
  113. package/dist/logging/logger.js +279 -0
  114. package/dist/logging/logger.js.map +1 -0
  115. package/dist/logging/loggerInterface.d.ts +33 -0
  116. package/dist/logging/loggerInterface.d.ts.map +1 -0
  117. package/dist/logging/loggerInterface.js +2 -0
  118. package/dist/logging/loggerInterface.js.map +1 -0
  119. package/dist/memory/inMemoryRelationStore.d.ts +51 -0
  120. package/dist/memory/inMemoryRelationStore.d.ts.map +1 -0
  121. package/dist/memory/inMemoryRelationStore.js +65 -0
  122. package/dist/memory/inMemoryRelationStore.js.map +1 -0
  123. package/dist/memory/inMemoryStorage.d.ts +97 -0
  124. package/dist/memory/inMemoryStorage.d.ts.map +1 -0
  125. package/dist/memory/inMemoryStorage.js +177 -0
  126. package/dist/memory/inMemoryStorage.js.map +1 -0
  127. package/dist/memory/loader.d.ts +49 -0
  128. package/dist/memory/loader.d.ts.map +1 -0
  129. package/dist/memory/loader.js +93 -0
  130. package/dist/memory/loader.js.map +1 -0
  131. package/dist/memory/projectManager.d.ts +182 -0
  132. package/dist/memory/projectManager.d.ts.map +1 -0
  133. package/dist/memory/projectManager.js +441 -0
  134. package/dist/memory/projectManager.js.map +1 -0
  135. package/dist/memory/recall.d.ts +77 -0
  136. package/dist/memory/recall.d.ts.map +1 -0
  137. package/dist/memory/recall.js +147 -0
  138. package/dist/memory/recall.js.map +1 -0
  139. package/dist/memory/relationStore.d.ts +78 -0
  140. package/dist/memory/relationStore.d.ts.map +1 -0
  141. package/dist/memory/relationStore.js +2 -0
  142. package/dist/memory/relationStore.js.map +1 -0
  143. package/dist/memory/sessionStore.d.ts +84 -0
  144. package/dist/memory/sessionStore.d.ts.map +1 -0
  145. package/dist/memory/sessionStore.js +2 -0
  146. package/dist/memory/sessionStore.js.map +1 -0
  147. package/dist/memory/storageInterface.d.ts +107 -0
  148. package/dist/memory/storageInterface.d.ts.map +1 -0
  149. package/dist/memory/storageInterface.js +2 -0
  150. package/dist/memory/storageInterface.js.map +1 -0
  151. package/dist/memory/store.d.ts +50 -0
  152. package/dist/memory/store.d.ts.map +1 -0
  153. package/dist/memory/store.js +160 -0
  154. package/dist/memory/store.js.map +1 -0
  155. package/dist/memory/types.d.ts +189 -0
  156. package/dist/memory/types.d.ts.map +1 -0
  157. package/dist/memory/types.js +230 -0
  158. package/dist/memory/types.js.map +1 -0
  159. package/dist/memory/userProfile.d.ts +156 -0
  160. package/dist/memory/userProfile.d.ts.map +1 -0
  161. package/dist/memory/userProfile.js +315 -0
  162. package/dist/memory/userProfile.js.map +1 -0
  163. package/dist/memory/vectorStore.d.ts +75 -0
  164. package/dist/memory/vectorStore.d.ts.map +1 -0
  165. package/dist/memory/vectorStore.js +144 -0
  166. package/dist/memory/vectorStore.js.map +1 -0
  167. package/dist/persona/personaManager.d.ts +121 -0
  168. package/dist/persona/personaManager.d.ts.map +1 -0
  169. package/dist/persona/personaManager.js +349 -0
  170. package/dist/persona/personaManager.js.map +1 -0
  171. package/dist/persona/types.d.ts +32 -0
  172. package/dist/persona/types.d.ts.map +1 -0
  173. package/dist/persona/types.js +5 -0
  174. package/dist/persona/types.js.map +1 -0
  175. package/dist/security/pathGuard.d.ts +121 -0
  176. package/dist/security/pathGuard.d.ts.map +1 -0
  177. package/dist/security/pathGuard.js +276 -0
  178. package/dist/security/pathGuard.js.map +1 -0
  179. package/dist/skill/skillManager.d.ts +82 -0
  180. package/dist/skill/skillManager.d.ts.map +1 -0
  181. package/dist/skill/skillManager.js +198 -0
  182. package/dist/skill/skillManager.js.map +1 -0
  183. package/dist/skill/types.d.ts +28 -0
  184. package/dist/skill/types.d.ts.map +1 -0
  185. package/dist/skill/types.js +5 -0
  186. package/dist/skill/types.js.map +1 -0
  187. package/dist/utils/errors.d.ts +86 -0
  188. package/dist/utils/errors.d.ts.map +1 -0
  189. package/dist/utils/errors.js +143 -0
  190. package/dist/utils/errors.js.map +1 -0
  191. package/dist/utils/eventEmitter.d.ts +87 -0
  192. package/dist/utils/eventEmitter.d.ts.map +1 -0
  193. package/dist/utils/eventEmitter.js +79 -0
  194. package/dist/utils/eventEmitter.js.map +1 -0
  195. package/dist/utils/frontmatter.d.ts +24 -0
  196. package/dist/utils/frontmatter.d.ts.map +1 -0
  197. package/dist/utils/frontmatter.js +44 -0
  198. package/dist/utils/frontmatter.js.map +1 -0
  199. package/dist/utils/json.d.ts +20 -0
  200. package/dist/utils/json.d.ts.map +1 -0
  201. package/dist/utils/json.js +65 -0
  202. package/dist/utils/json.js.map +1 -0
  203. package/dist/utils/loggerHolder.d.ts +37 -0
  204. package/dist/utils/loggerHolder.d.ts.map +1 -0
  205. package/dist/utils/loggerHolder.js +49 -0
  206. package/dist/utils/loggerHolder.js.map +1 -0
  207. package/dist/utils/math.d.ts +5 -0
  208. package/dist/utils/math.d.ts.map +1 -0
  209. package/dist/utils/math.js +19 -0
  210. package/dist/utils/math.js.map +1 -0
  211. package/dist/utils/path.d.ts +28 -0
  212. package/dist/utils/path.d.ts.map +1 -0
  213. package/dist/utils/path.js +33 -0
  214. package/dist/utils/path.js.map +1 -0
  215. package/dist/utils/safeTimer.d.ts +26 -0
  216. package/dist/utils/safeTimer.d.ts.map +1 -0
  217. package/dist/utils/safeTimer.js +49 -0
  218. package/dist/utils/safeTimer.js.map +1 -0
  219. package/dist/utils/scanner.d.ts +54 -0
  220. package/dist/utils/scanner.d.ts.map +1 -0
  221. package/dist/utils/scanner.js +115 -0
  222. package/dist/utils/scanner.js.map +1 -0
  223. package/dist/utils/segmenter.d.ts +30 -0
  224. package/dist/utils/segmenter.d.ts.map +1 -0
  225. package/dist/utils/segmenter.js +80 -0
  226. package/dist/utils/segmenter.js.map +1 -0
  227. package/dist/utils/strings.d.ts +18 -0
  228. package/dist/utils/strings.d.ts.map +1 -0
  229. package/dist/utils/strings.js +25 -0
  230. package/dist/utils/strings.js.map +1 -0
  231. package/dist/utils/time.d.ts +23 -0
  232. package/dist/utils/time.d.ts.map +1 -0
  233. package/dist/utils/time.js +31 -0
  234. package/dist/utils/time.js.map +1 -0
  235. package/dist/utils/toError.d.ts +13 -0
  236. package/dist/utils/toError.d.ts.map +1 -0
  237. package/dist/utils/toError.js +22 -0
  238. package/dist/utils/toError.js.map +1 -0
  239. package/package.json +73 -0
@@ -0,0 +1,144 @@
1
+ /**
2
+ * 向量存储 — 纯 JS 实现,内存 + JSON 持久化
3
+ *
4
+ * M-206:语义检索的向量索引层
5
+ * - 存储记忆 ID → 向量的映射
6
+ * - 支持余弦相似度搜索(topK)
7
+ * - 持久化到 JSON 文件(冷启动时加载)
8
+ *
9
+ * 设计原则:
10
+ * - 0 新 npm 依赖(不引入 sqlite-vec / LanceDB 等外部向量库)
11
+ * - 单用户本地场景,5k 条记录内纯 JS 余弦相似度 < 10ms
12
+ * - 向量维度由 embedding 模型决定,存储层不关心
13
+ *
14
+ * 详见 ADR-002 · 存储层抽象(向量检索备选方案)
15
+ * 详见 ADR-013 · 记忆归档三步价值过滤
16
+ */
17
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
18
+ import { dirname } from 'node:path';
19
+ import { logger } from '../logging/logger.js';
20
+ import { cosineSimilarity } from '../utils/math.js';
21
+ /**
22
+ * 向量存储
23
+ *
24
+ * 纯 JS 实现,内存中维护向量索引,定期持久化到 JSON 文件
25
+ * 适用于单用户本地场景(5k 条记录以内)
26
+ *
27
+ * 依赖 EmbeddingService 接口(依赖倒置,与 llm/ 层解耦)
28
+ */
29
+ export class VectorStore {
30
+ storePath;
31
+ embeddingProvider;
32
+ /** 内存中的向量索引 */
33
+ entries = new Map();
34
+ /** 向量维度(由第一个插入的向量决定) */
35
+ dimension = 0;
36
+ /** 是否有未持久化的变更 */
37
+ dirty = false;
38
+ constructor(storePath, embeddingProvider) {
39
+ this.storePath = storePath;
40
+ this.embeddingProvider = embeddingProvider;
41
+ }
42
+ /**
43
+ * 从 JSON 文件加载向量索引(冷启动)
44
+ */
45
+ async load() {
46
+ try {
47
+ const content = await readFile(this.storePath, 'utf-8');
48
+ const data = JSON.parse(content);
49
+ this.dimension = data.dimension;
50
+ this.entries.clear();
51
+ for (const entry of data.entries) {
52
+ this.entries.set(entry.id, entry.vector);
53
+ }
54
+ this.dirty = false;
55
+ logger.info({ count: this.entries.size, dimension: this.dimension }, '向量索引加载完成');
56
+ }
57
+ catch {
58
+ // 文件不存在或格式错误,从空开始
59
+ logger.info({ path: this.storePath }, '向量索引文件不存在,从空开始');
60
+ }
61
+ }
62
+ /**
63
+ * 持久化向量索引到 JSON 文件
64
+ */
65
+ async save() {
66
+ if (!this.dirty)
67
+ return;
68
+ const data = {
69
+ version: 1,
70
+ dimension: this.dimension,
71
+ entries: Array.from(this.entries.entries()).map(([id, vector]) => ({ id, vector })),
72
+ };
73
+ await mkdir(dirname(this.storePath), { recursive: true });
74
+ await writeFile(this.storePath, JSON.stringify(data), 'utf-8');
75
+ this.dirty = false;
76
+ logger.info({ count: this.entries.size }, '向量索引持久化完成');
77
+ }
78
+ /**
79
+ * 为文本生成向量并存储
80
+ * @param id 记忆 ID
81
+ * @param text 待嵌入的文本
82
+ */
83
+ async upsert(id, text) {
84
+ const vector = await this.embeddingProvider.embed(text);
85
+ if (this.dimension === 0) {
86
+ this.dimension = vector.length;
87
+ }
88
+ this.entries.set(id, vector);
89
+ this.dirty = true;
90
+ }
91
+ /**
92
+ * 批量嵌入并存储
93
+ * @param items ID + 文本对
94
+ */
95
+ async batchUpsert(items) {
96
+ const texts = items.map((item) => item.text);
97
+ const results = await this.embeddingProvider.batchEmbed(texts);
98
+ for (let i = 0; i < items.length; i++) {
99
+ const result = results[i];
100
+ const item = items[i];
101
+ if (!result || !item)
102
+ continue;
103
+ if (this.dimension === 0) {
104
+ this.dimension = result.vector.length;
105
+ }
106
+ this.entries.set(item.id, result.vector);
107
+ }
108
+ this.dirty = true;
109
+ }
110
+ /**
111
+ * 删除向量
112
+ */
113
+ delete(id) {
114
+ this.entries.delete(id);
115
+ this.dirty = true;
116
+ }
117
+ /**
118
+ * 语义搜索:基于查询文本的向量,返回 topK 最相似的 ID
119
+ * @param query 查询文本
120
+ * @param topK 返回数量上限
121
+ * @param minSimilarity 最低相似度阈值(0~1)
122
+ * @returns ID + 相似度 对的数组,按相似度降序排列
123
+ */
124
+ async search(query, topK = 5, minSimilarity = 0.3) {
125
+ const queryVector = await this.embeddingProvider.embed(query);
126
+ const scored = [];
127
+ for (const [id, vector] of this.entries) {
128
+ const similarity = cosineSimilarity(queryVector, vector);
129
+ if (similarity >= minSimilarity) {
130
+ scored.push({ id, similarity });
131
+ }
132
+ }
133
+ // 按相似度降序排列,取 topK
134
+ scored.sort((a, b) => b.similarity - a.similarity);
135
+ return scored.slice(0, topK);
136
+ }
137
+ /**
138
+ * 获取存储的向量数量
139
+ */
140
+ get size() {
141
+ return this.entries.size;
142
+ }
143
+ }
144
+ //# sourceMappingURL=vectorStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vectorStore.js","sourceRoot":"","sources":["../../src/memory/vectorStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,121 @@
1
+ import type { IMemoryStorage } from '../memory/storageInterface.js';
2
+ import type { Persona, PersonaMode } from '../persona/types.js';
3
+ /**
4
+ * 角色管理器(personas/ + SQLite + 关键词匹配)
5
+ */
6
+ export declare class PersonaManager {
7
+ private readonly configDir?;
8
+ private readonly index?;
9
+ /** 当前激活的角色 */
10
+ private activePersona;
11
+ /** 角色列表缓存(启动时扫描一次) */
12
+ private personaList;
13
+ /** 激活模式 */
14
+ private mode;
15
+ /** 角色切换时间戳列表(用于时间窗口缓冲) */
16
+ private switchTimestamps;
17
+ /** 缓冲区开关(60s 内 3 次切换后锁定) */
18
+ private switchLocked;
19
+ /** 锁定恢复计时器 */
20
+ private unlockTimer;
21
+ /** 时间窗口:60 秒 */
22
+ private static readonly SWITCH_WINDOW_MS;
23
+ /** 窗口内最大切换次数 */
24
+ private static readonly MAX_SWITCHES_IN_WINDOW;
25
+ /** 锁定后自动恢复时间:5 分钟 */
26
+ private static readonly AUTO_UNLOCK_MS;
27
+ /**
28
+ * @param configDir 配置目录(角色文件在 <configDir>/personas/ 下)
29
+ * @param index SQLite 索引(用于写入 persona 记忆)
30
+ */
31
+ constructor(configDir?: string | undefined, index?: IMemoryStorage | undefined);
32
+ /**
33
+ * 启动时加载:扫描目录 + 激活指定角色 + 写入 SQLite
34
+ *
35
+ * @param activePersona 要激活的角色名(可选,不传则使用第一个找到的角色)
36
+ * @returns 激活角色的 system prompt 段
37
+ */
38
+ load(activePersona?: string): Promise<string>;
39
+ /**
40
+ * 获取当前激活的角色名(用于 bootstrap 过滤)
41
+ */
42
+ get activeName(): string;
43
+ /**
44
+ * 获取当前激活角色对象(Phase 2.1:AffectController 需要 traits 字段)
45
+ *
46
+ * 返回 null 时表示未加载任何角色(使用默认行为)。
47
+ */
48
+ getActive(): Persona | null;
49
+ /**
50
+ * 切换角色(带时间窗口缓冲)
51
+ *
52
+ * 错误策略统一(IX-03):角色不存在时抛 MemoraError,与 switchProject 一致。
53
+ * 交换锁定时仍返回当前 prompt(非错误,是限流保护)。
54
+ *
55
+ * @param name 角色名
56
+ * @returns 新角色的 system prompt 段
57
+ * @throws MemoraError 如果角色不存在
58
+ */
59
+ switchPersona(name: string): string;
60
+ /**
61
+ * 根据用户输入自动匹配最合适的角色
62
+ *
63
+ * 匹配条件:
64
+ * - 当前模式为 'auto'(非手动锁定)
65
+ * - 缓冲区未锁定
66
+ * - 匹配得分 ≥ 0.5
67
+ * - 匹配的角色与当前角色不同
68
+ *
69
+ * @param userInput 用户输入文本
70
+ * @returns 匹配的角色名,无匹配返回 null
71
+ */
72
+ autoMatch(userInput: string): string | null;
73
+ /**
74
+ * 设置激活模式
75
+ *
76
+ * @param mode 'auto'(自动匹配)| 'manual'(手动固定)
77
+ */
78
+ setMode(mode: PersonaMode): void;
79
+ /** 获取当前激活模式 */
80
+ get currentMode(): PersonaMode;
81
+ /**
82
+ * 获取当前激活的角色
83
+ */
84
+ get active(): Persona | null;
85
+ /**
86
+ * 获取角色列表
87
+ */
88
+ get list(): Persona[];
89
+ /**
90
+ * 清理定时器资源(Agent.close() 时调用)
91
+ *
92
+ * PersonaManager 持有 unlockTimer(角色切换防抖锁的自动恢复计时器),
93
+ * 若不清理,Agent 关闭后定时器仍会触发回调,在已关闭的实例上执行引发异常。
94
+ */
95
+ close(): void;
96
+ /**
97
+ * 构建 system prompt 中的角色段
98
+ */
99
+ buildSystemPrompt(name?: string): string;
100
+ /**
101
+ * 记录一次角色切换(时间窗口缓冲)
102
+ */
103
+ private recordSwitch;
104
+ /**
105
+ * 扫描单层目录,加载角色列表
106
+ */
107
+ private scanPersonas;
108
+ /**
109
+ * 将所有角色写入 SQLite 索引
110
+ */
111
+ private writeAllToIndex;
112
+ /**
113
+ * 将单个角色写入 SQLite 索引
114
+ */
115
+ private writePersonaToIndex;
116
+ /**
117
+ * 创建默认角色
118
+ */
119
+ private createDefaultPersona;
120
+ }
121
+ //# sourceMappingURL=personaManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"personaManager.d.ts","sourceRoot":"","sources":["../../src/persona/personaManager.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAKnE,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA4B/D;;GAEG;AACH,qBAAa,cAAc;IA0BvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IAC3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;IA1BzB,cAAc;IACd,OAAO,CAAC,aAAa,CAAwB;IAC7C,sBAAsB;IACtB,OAAO,CAAC,WAAW,CAAiB;IACpC,WAAW;IACX,OAAO,CAAC,IAAI,CAAuB;IACnC,0BAA0B;IAC1B,OAAO,CAAC,gBAAgB,CAAgB;IACxC,4BAA4B;IAC5B,OAAO,CAAC,YAAY,CAAS;IAC7B,cAAc;IACd,OAAO,CAAC,WAAW,CAA8C;IAEjE,gBAAgB;IAChB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAClD,gBAAgB;IAChB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAK;IACnD,qBAAqB;IACrB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAW;IAEjD;;;OAGG;gBAEgB,SAAS,CAAC,EAAE,MAAM,YAAA,EAClB,KAAK,CAAC,EAAE,cAAc,YAAA;IAGzC;;;;;OAKG;IACG,IAAI,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqCnD;;OAEG;IACH,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED;;;;OAIG;IACH,SAAS,IAAI,OAAO,GAAG,IAAI;IAI3B;;;;;;;;;OASG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAyBnC;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IA8B3C;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IAUhC,eAAe;IACf,IAAI,WAAW,IAAI,WAAW,CAE7B;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,OAAO,GAAG,IAAI,CAE3B;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,EAAE,CAEpB;IAED;;;;;OAKG;IACH,KAAK,IAAI,IAAI;IAOb;;OAEG;IACH,iBAAiB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;IAUxC;;OAEG;IACH,OAAO,CAAC,YAAY;IAqBpB;;OAEG;YACW,YAAY;IAyB1B;;OAEG;YACW,eAAe;IAQ7B;;OAEG;YACW,mBAAmB;IAejC;;OAEG;IACH,OAAO,CAAC,oBAAoB;CAU7B"}
@@ -0,0 +1,349 @@
1
+ /**
2
+ * 角色管理器 — 加载、切换、注入角色人格(personas/ 目录 + SQLite 存储)
3
+ *
4
+ * 职责:
5
+ * - 从 configDir/personas/*.md 加载角色文件
6
+ * - 解析 frontmatter(name / keywords / description)
7
+ * - 写入 SQLite 索引(source: persona, score: 1.0)
8
+ * - 将激活角色注入到 system prompt 顶部
9
+ * - 支持运行时切换角色 + 关键词自动匹配
10
+ *
11
+ * 设计原则(architecture_philosophy_rules.md §1):
12
+ * - Persona 遵循"万物皆记忆"——存入 SQLite 作为 persona 来源记忆
13
+ * - 召回管线做特殊处理:bootstrap 只取当前激活角色的 1 条 persona 记忆
14
+ * - 角色可被会话关键词动态匹配自动切换,也可手动指定
15
+ *
16
+ * 目录约定:
17
+ * - 单层角色:只有宿主程序级 <configDir>/personas/*.md
18
+ * - 目录名 personas/ 与代码 Persona 术语一致,区别于用户身份信息
19
+ */
20
+ import { scoreByKeywords } from '../utils/segmenter.js';
21
+ import { SOURCE_LABELS } from '../memory/types.js';
22
+ import { logger } from '../logging/logger.js';
23
+ import { configError } from '../utils/errors.js';
24
+ import { scanMarkdownDir, parseKeywords, resolveSubdir } from '../utils/scanner.js';
25
+ import { safeSetTimeout, clearSafeTimeout } from '../utils/safeTimer.js';
26
+ /**
27
+ * 从 frontmatter 解析 traits.* 键值对
28
+ *
29
+ * 遍历 frontmatter 中以 "traits." 开头的键,提取数值。
30
+ * 非数值或超出 0-1 范围的值被静默忽略(防御性解析)。
31
+ *
32
+ * @param fm frontmatter 键值对映射
33
+ * @returns traits 对象,无有效键时返回 undefined
34
+ */
35
+ function parseTraits(fm) {
36
+ const traits = {};
37
+ for (const [key, value] of Object.entries(fm)) {
38
+ if (!key.startsWith('traits.'))
39
+ continue;
40
+ const traitName = key.slice(7); // 去掉 'traits.' 前缀
41
+ if (!traitName)
42
+ continue;
43
+ const num = Number(value);
44
+ // 防御性校验:必须是有效数值且在 0-1 范围内
45
+ if (Number.isFinite(num) && num >= 0 && num <= 1) {
46
+ traits[traitName] = num;
47
+ }
48
+ }
49
+ return Object.keys(traits).length > 0 ? traits : undefined;
50
+ }
51
+ /**
52
+ * 角色管理器(personas/ + SQLite + 关键词匹配)
53
+ */
54
+ export class PersonaManager {
55
+ configDir;
56
+ index;
57
+ /** 当前激活的角色 */
58
+ activePersona = null;
59
+ /** 角色列表缓存(启动时扫描一次) */
60
+ personaList = [];
61
+ /** 激活模式 */
62
+ mode = 'auto';
63
+ /** 角色切换时间戳列表(用于时间窗口缓冲) */
64
+ switchTimestamps = [];
65
+ /** 缓冲区开关(60s 内 3 次切换后锁定) */
66
+ switchLocked = false;
67
+ /** 锁定恢复计时器 */
68
+ unlockTimer = null;
69
+ /** 时间窗口:60 秒 */
70
+ static SWITCH_WINDOW_MS = 60_000;
71
+ /** 窗口内最大切换次数 */
72
+ static MAX_SWITCHES_IN_WINDOW = 3;
73
+ /** 锁定后自动恢复时间:5 分钟 */
74
+ static AUTO_UNLOCK_MS = 300_000;
75
+ /**
76
+ * @param configDir 配置目录(角色文件在 <configDir>/personas/ 下)
77
+ * @param index SQLite 索引(用于写入 persona 记忆)
78
+ */
79
+ constructor(configDir, index) {
80
+ this.configDir = configDir;
81
+ this.index = index;
82
+ }
83
+ /**
84
+ * 启动时加载:扫描目录 + 激活指定角色 + 写入 SQLite
85
+ *
86
+ * @param activePersona 要激活的角色名(可选,不传则使用第一个找到的角色)
87
+ * @returns 激活角色的 system prompt 段
88
+ */
89
+ async load(activePersona) {
90
+ this.personaList = await this.scanPersonas();
91
+ if (this.personaList.length === 0) {
92
+ logger.warn({ personaCount: 0 }, '未找到任何角色文件,将使用默认角色');
93
+ this.activePersona = this.createDefaultPersona();
94
+ await this.writePersonaToIndex(this.activePersona);
95
+ return this.buildSystemPrompt();
96
+ }
97
+ logger.info({ count: this.personaList.length, names: this.personaList.map((p) => p.name) }, '角色文件加载完成');
98
+ // 写入 SQLite 索引(persona 遵循万物皆记忆)
99
+ await this.writeAllToIndex();
100
+ // 激活指定角色
101
+ if (activePersona) {
102
+ const found = this.personaList.find((p) => p.name === activePersona);
103
+ if (found) {
104
+ this.activePersona = found;
105
+ }
106
+ else {
107
+ logger.warn({ requested: activePersona }, '未找到指定角色,使用第一个');
108
+ // QC-17 移除非空断言:personaList 已在第 72 行检查非空
109
+ this.activePersona = this.personaList[0] ?? this.createDefaultPersona();
110
+ }
111
+ }
112
+ else {
113
+ // QC-17 移除非空断言:personaList 已在第 72 行检查非空
114
+ this.activePersona = this.personaList[0] ?? this.createDefaultPersona();
115
+ }
116
+ logger.info({ persona: this.activePersona.name }, '角色已激活');
117
+ return this.buildSystemPrompt();
118
+ }
119
+ /**
120
+ * 获取当前激活的角色名(用于 bootstrap 过滤)
121
+ */
122
+ get activeName() {
123
+ return this.activePersona?.name ?? 'default';
124
+ }
125
+ /**
126
+ * 获取当前激活角色对象(Phase 2.1:AffectController 需要 traits 字段)
127
+ *
128
+ * 返回 null 时表示未加载任何角色(使用默认行为)。
129
+ */
130
+ getActive() {
131
+ return this.activePersona;
132
+ }
133
+ /**
134
+ * 切换角色(带时间窗口缓冲)
135
+ *
136
+ * 错误策略统一(IX-03):角色不存在时抛 MemoraError,与 switchProject 一致。
137
+ * 交换锁定时仍返回当前 prompt(非错误,是限流保护)。
138
+ *
139
+ * @param name 角色名
140
+ * @returns 新角色的 system prompt 段
141
+ * @throws MemoraError 如果角色不存在
142
+ */
143
+ switchPersona(name) {
144
+ // 缓冲区检查(限流保护,非错误)
145
+ if (this.switchLocked) {
146
+ logger.info({ persona: name }, '角色切换已锁定(60s 内超过 3 次),保持当前');
147
+ return this.buildSystemPrompt();
148
+ }
149
+ const found = this.personaList.find((p) => p.name === name);
150
+ if (!found) {
151
+ // 统一错误策略:找不到目标时抛错,而非静默保持当前
152
+ throw configError('角色切换失败', `角色 "${name}" 不存在`, [
153
+ '使用 persona.list 查看可用角色',
154
+ '在 agent-config/personas/ 目录下创建该角色配置文件',
155
+ ]);
156
+ }
157
+ if (this.activePersona?.name === name) {
158
+ return this.buildSystemPrompt(); // 同一角色,不需要切换
159
+ }
160
+ this.activePersona = found;
161
+ this.recordSwitch();
162
+ logger.info({ persona: name }, '角色已切换');
163
+ return this.buildSystemPrompt();
164
+ }
165
+ /**
166
+ * 根据用户输入自动匹配最合适的角色
167
+ *
168
+ * 匹配条件:
169
+ * - 当前模式为 'auto'(非手动锁定)
170
+ * - 缓冲区未锁定
171
+ * - 匹配得分 ≥ 0.5
172
+ * - 匹配的角色与当前角色不同
173
+ *
174
+ * @param userInput 用户输入文本
175
+ * @returns 匹配的角色名,无匹配返回 null
176
+ */
177
+ autoMatch(userInput) {
178
+ if (this.mode !== 'auto')
179
+ return null;
180
+ if (this.switchLocked)
181
+ return null;
182
+ if (this.personaList.length === 0)
183
+ return null;
184
+ const matches = [];
185
+ for (const persona of this.personaList) {
186
+ if (persona.keywords.length === 0)
187
+ continue;
188
+ const score = scoreByKeywords(userInput, persona.keywords);
189
+ if (score > 0) {
190
+ matches.push({ name: persona.name, score });
191
+ }
192
+ }
193
+ if (matches.length === 0)
194
+ return null;
195
+ matches.sort((a, b) => b.score - a.score);
196
+ // QC-17 移除非空断言:matches 已在第 174 行检查非空
197
+ const best = matches[0];
198
+ if (!best)
199
+ return null;
200
+ if (best.score < 0.5)
201
+ return null;
202
+ if (this.activePersona?.name === best.name)
203
+ return null;
204
+ return best.name;
205
+ }
206
+ /**
207
+ * 设置激活模式
208
+ *
209
+ * @param mode 'auto'(自动匹配)| 'manual'(手动固定)
210
+ */
211
+ setMode(mode) {
212
+ this.mode = mode;
213
+ // 切回自动模式时清除锁定状态
214
+ if (mode === 'auto' && this.switchLocked) {
215
+ this.switchLocked = false;
216
+ this.switchTimestamps = [];
217
+ logger.info({ mode: this.mode }, '角色切换锁定已解除(模式切回自动)');
218
+ }
219
+ }
220
+ /** 获取当前激活模式 */
221
+ get currentMode() {
222
+ return this.mode;
223
+ }
224
+ /**
225
+ * 获取当前激活的角色
226
+ */
227
+ get active() {
228
+ return this.activePersona;
229
+ }
230
+ /**
231
+ * 获取角色列表
232
+ */
233
+ get list() {
234
+ return this.personaList;
235
+ }
236
+ /**
237
+ * 清理定时器资源(Agent.close() 时调用)
238
+ *
239
+ * PersonaManager 持有 unlockTimer(角色切换防抖锁的自动恢复计时器),
240
+ * 若不清理,Agent 关闭后定时器仍会触发回调,在已关闭的实例上执行引发异常。
241
+ */
242
+ close() {
243
+ if (this.unlockTimer) {
244
+ clearSafeTimeout(this.unlockTimer);
245
+ this.unlockTimer = null;
246
+ }
247
+ }
248
+ /**
249
+ * 构建 system prompt 中的角色段
250
+ */
251
+ buildSystemPrompt(name) {
252
+ const p = name ? this.personaList.find((item) => item.name === name) : this.activePersona;
253
+ if (!p)
254
+ return '';
255
+ const meta = [`【当前角色】${p.name}`];
256
+ if (p.description)
257
+ meta.push(p.description);
258
+ return `${meta.join(' · ')}\n\n${p.content}`;
259
+ }
260
+ // ── 私有方法 ──────────────────────────────────────
261
+ /**
262
+ * 记录一次角色切换(时间窗口缓冲)
263
+ */
264
+ recordSwitch() {
265
+ const now = Date.now();
266
+ // 清理过期记录
267
+ this.switchTimestamps = this.switchTimestamps.filter((t) => now - t < PersonaManager.SWITCH_WINDOW_MS);
268
+ this.switchTimestamps.push(now);
269
+ if (this.switchTimestamps.length >= PersonaManager.MAX_SWITCHES_IN_WINDOW) {
270
+ logger.warn({ count: this.switchTimestamps.length }, '角色切换过于频繁,锁定 5 分钟');
271
+ this.switchLocked = true;
272
+ // 5 分钟后自动解锁
273
+ if (this.unlockTimer)
274
+ clearSafeTimeout(this.unlockTimer);
275
+ this.unlockTimer = safeSetTimeout(() => {
276
+ this.switchLocked = false;
277
+ this.switchTimestamps = [];
278
+ logger.info({ mode: this.mode }, '角色切换锁定已自动解除');
279
+ }, PersonaManager.AUTO_UNLOCK_MS);
280
+ }
281
+ }
282
+ /**
283
+ * 扫描单层目录,加载角色列表
284
+ */
285
+ async scanPersonas() {
286
+ const list = [];
287
+ const personasDir = resolveSubdir(this.configDir, 'personas');
288
+ if (!personasDir)
289
+ return list;
290
+ const entries = await scanMarkdownDir(personasDir);
291
+ for (const entry of entries) {
292
+ const fm = entry.frontmatter;
293
+ list.push({
294
+ name: entry.name,
295
+ id: fm['id'] ?? `persona:${entry.name}`,
296
+ description: fm['description'],
297
+ keywords: parseKeywords(fm),
298
+ content: entry.body.trim(),
299
+ filePath: entry.filePath,
300
+ // Phase 2.1:解析 traits.* 键值对(如 traits.playfulness: 0.7)
301
+ traits: parseTraits(fm),
302
+ });
303
+ }
304
+ return list;
305
+ }
306
+ /**
307
+ * 将所有角色写入 SQLite 索引
308
+ */
309
+ async writeAllToIndex() {
310
+ if (!this.index)
311
+ return;
312
+ for (const persona of this.personaList) {
313
+ await this.writePersonaToIndex(persona);
314
+ }
315
+ logger.info({ count: this.personaList.length }, '角色记忆已写入 SQLite');
316
+ }
317
+ /**
318
+ * 将单个角色写入 SQLite 索引
319
+ */
320
+ async writePersonaToIndex(persona) {
321
+ if (!this.index)
322
+ return;
323
+ const now = new Date().toISOString();
324
+ const memory = {
325
+ id: persona.id,
326
+ content: persona.content,
327
+ source: SOURCE_LABELS.PERSONA,
328
+ name: persona.name,
329
+ createdAt: now,
330
+ accessedAt: now,
331
+ score: 1.0,
332
+ };
333
+ this.index.upsert(memory);
334
+ }
335
+ /**
336
+ * 创建默认角色
337
+ */
338
+ createDefaultPersona() {
339
+ return {
340
+ name: 'default',
341
+ id: 'persona:default',
342
+ description: '默认通用助手',
343
+ keywords: [],
344
+ content: '你是一个通用 AI 助手,以专业、友好的态度回应用户。',
345
+ filePath: '(built-in)',
346
+ };
347
+ }
348
+ }
349
+ //# sourceMappingURL=personaManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"personaManager.js","sourceRoot":"","sources":["../../src/persona/personaManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * 角色模块类型定义
3
+ */
4
+ /** 角色定义(从 personas/*.md frontmatter 解析) */
5
+ export interface Persona {
6
+ /** 角色名(文件名去 .md) */
7
+ name: string;
8
+ /** 唯一 id(用于 SQLite 索引) */
9
+ id: string;
10
+ /** 角色描述(可选) */
11
+ description?: string;
12
+ /** 关键词(用于自动匹配切换) */
13
+ keywords: string[];
14
+ /** 人格正文(frontmatter 之后的 markdown 内容) */
15
+ content: string;
16
+ /** 来源路径 */
17
+ filePath: string;
18
+ /**
19
+ * 角色特质(Phase 2.1:AffectController 情感基调推导)
20
+ *
21
+ * 开放字符串键值对,非封闭枚举。预设键:
22
+ * - playfulness: 调皮度 0-1(默认 0.3)
23
+ * - warmth: 温暖度 0-1(默认 0.5)
24
+ * - directness: 直接度 0-1(默认 0.5)
25
+ *
26
+ * 宿主可自由扩展。从 persona .md 的 frontmatter 解析(如 traits.playfulness: 0.7)。
27
+ */
28
+ traits?: Record<string, number>;
29
+ }
30
+ /** 角色激活模式 */
31
+ export type PersonaMode = 'auto' | 'manual';
32
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/persona/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,2CAA2C;AAC3C,MAAM,WAAW,OAAO;IACtB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,0BAA0B;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,eAAe;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,aAAa;AACb,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAC"}