@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.
- package/LICENSE +21 -0
- package/README.md +148 -0
- package/dist/agent/agent.d.ts +343 -0
- package/dist/agent/agent.d.ts.map +1 -0
- package/dist/agent/agent.js +893 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/assembler.d.ts +77 -0
- package/dist/agent/assembler.d.ts.map +1 -0
- package/dist/agent/assembler.js +115 -0
- package/dist/agent/assembler.js.map +1 -0
- package/dist/agent/builtinToolHandlers.d.ts +96 -0
- package/dist/agent/builtinToolHandlers.d.ts.map +1 -0
- package/dist/agent/builtinToolHandlers.js +388 -0
- package/dist/agent/builtinToolHandlers.js.map +1 -0
- package/dist/agent/builtinTools.d.ts +35 -0
- package/dist/agent/builtinTools.d.ts.map +1 -0
- package/dist/agent/builtinTools.js +75 -0
- package/dist/agent/builtinTools.js.map +1 -0
- package/dist/agent/constants.d.ts +67 -0
- package/dist/agent/constants.d.ts.map +1 -0
- package/dist/agent/constants.js +67 -0
- package/dist/agent/constants.js.map +1 -0
- package/dist/agent/contextManager.d.ts +130 -0
- package/dist/agent/contextManager.d.ts.map +1 -0
- package/dist/agent/contextManager.js +287 -0
- package/dist/agent/contextManager.js.map +1 -0
- package/dist/agent/loop.d.ts +288 -0
- package/dist/agent/loop.d.ts.map +1 -0
- package/dist/agent/loop.js +756 -0
- package/dist/agent/loop.js.map +1 -0
- package/dist/agent/managers/autoConfigRefiner.d.ts +39 -0
- package/dist/agent/managers/autoConfigRefiner.d.ts.map +1 -0
- package/dist/agent/managers/autoConfigRefiner.js +150 -0
- package/dist/agent/managers/autoConfigRefiner.js.map +1 -0
- package/dist/agent/managers/configManager.d.ts +114 -0
- package/dist/agent/managers/configManager.d.ts.map +1 -0
- package/dist/agent/managers/configManager.js +186 -0
- package/dist/agent/managers/configManager.js.map +1 -0
- package/dist/agent/managers/insightExtractor.d.ts +141 -0
- package/dist/agent/managers/insightExtractor.d.ts.map +1 -0
- package/dist/agent/managers/insightExtractor.js +420 -0
- package/dist/agent/managers/insightExtractor.js.map +1 -0
- package/dist/agent/managers/memoryAdvisor.d.ts +96 -0
- package/dist/agent/managers/memoryAdvisor.d.ts.map +1 -0
- package/dist/agent/managers/memoryAdvisor.js +198 -0
- package/dist/agent/managers/memoryAdvisor.js.map +1 -0
- package/dist/agent/managers/memoryInspector.d.ts +231 -0
- package/dist/agent/managers/memoryInspector.d.ts.map +1 -0
- package/dist/agent/managers/memoryInspector.js +327 -0
- package/dist/agent/managers/memoryInspector.js.map +1 -0
- package/dist/agent/managers/sessionManager.d.ts +89 -0
- package/dist/agent/managers/sessionManager.d.ts.map +1 -0
- package/dist/agent/managers/sessionManager.js +178 -0
- package/dist/agent/managers/sessionManager.js.map +1 -0
- package/dist/agent/managers/userFactExtractor.d.ts +25 -0
- package/dist/agent/managers/userFactExtractor.d.ts.map +1 -0
- package/dist/agent/managers/userFactExtractor.js +81 -0
- package/dist/agent/managers/userFactExtractor.js.map +1 -0
- package/dist/agent/managers/workProjection.d.ts +117 -0
- package/dist/agent/managers/workProjection.d.ts.map +1 -0
- package/dist/agent/managers/workProjection.js +290 -0
- package/dist/agent/managers/workProjection.js.map +1 -0
- package/dist/agent/messageHistory.d.ts +157 -0
- package/dist/agent/messageHistory.d.ts.map +1 -0
- package/dist/agent/messageHistory.js +288 -0
- package/dist/agent/messageHistory.js.map +1 -0
- package/dist/agent/toolExecutor.d.ts +137 -0
- package/dist/agent/toolExecutor.d.ts.map +1 -0
- package/dist/agent/toolExecutor.js +209 -0
- package/dist/agent/toolExecutor.js.map +1 -0
- package/dist/agent/tracer.d.ts +122 -0
- package/dist/agent/tracer.d.ts.map +1 -0
- package/dist/agent/tracer.js +64 -0
- package/dist/agent/tracer.js.map +1 -0
- package/dist/agent/types.d.ts +98 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +19 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/config/loader.d.ts +229 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +194 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/eval/evalTypes.d.ts +118 -0
- package/dist/eval/evalTypes.d.ts.map +1 -0
- package/dist/eval/evalTypes.js +102 -0
- package/dist/eval/evalTypes.js.map +1 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/embedding.d.ts +62 -0
- package/dist/llm/embedding.d.ts.map +1 -0
- package/dist/llm/embedding.js +162 -0
- package/dist/llm/embedding.js.map +1 -0
- package/dist/llm/factory.d.ts +39 -0
- package/dist/llm/factory.d.ts.map +1 -0
- package/dist/llm/factory.js +108 -0
- package/dist/llm/factory.js.map +1 -0
- package/dist/llm/openaiCompatible.d.ts +63 -0
- package/dist/llm/openaiCompatible.d.ts.map +1 -0
- package/dist/llm/openaiCompatible.js +340 -0
- package/dist/llm/openaiCompatible.js.map +1 -0
- package/dist/llm/provider.d.ts +91 -0
- package/dist/llm/provider.d.ts.map +1 -0
- package/dist/llm/provider.js +14 -0
- package/dist/llm/provider.js.map +1 -0
- package/dist/llm/types.d.ts +25 -0
- package/dist/llm/types.d.ts.map +1 -0
- package/dist/llm/types.js +7 -0
- package/dist/llm/types.js.map +1 -0
- package/dist/logging/logger.d.ts +39 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +279 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/logging/loggerInterface.d.ts +33 -0
- package/dist/logging/loggerInterface.d.ts.map +1 -0
- package/dist/logging/loggerInterface.js +2 -0
- package/dist/logging/loggerInterface.js.map +1 -0
- package/dist/memory/inMemoryRelationStore.d.ts +51 -0
- package/dist/memory/inMemoryRelationStore.d.ts.map +1 -0
- package/dist/memory/inMemoryRelationStore.js +65 -0
- package/dist/memory/inMemoryRelationStore.js.map +1 -0
- package/dist/memory/inMemoryStorage.d.ts +97 -0
- package/dist/memory/inMemoryStorage.d.ts.map +1 -0
- package/dist/memory/inMemoryStorage.js +177 -0
- package/dist/memory/inMemoryStorage.js.map +1 -0
- package/dist/memory/loader.d.ts +49 -0
- package/dist/memory/loader.d.ts.map +1 -0
- package/dist/memory/loader.js +93 -0
- package/dist/memory/loader.js.map +1 -0
- package/dist/memory/projectManager.d.ts +182 -0
- package/dist/memory/projectManager.d.ts.map +1 -0
- package/dist/memory/projectManager.js +441 -0
- package/dist/memory/projectManager.js.map +1 -0
- package/dist/memory/recall.d.ts +77 -0
- package/dist/memory/recall.d.ts.map +1 -0
- package/dist/memory/recall.js +147 -0
- package/dist/memory/recall.js.map +1 -0
- package/dist/memory/relationStore.d.ts +78 -0
- package/dist/memory/relationStore.d.ts.map +1 -0
- package/dist/memory/relationStore.js +2 -0
- package/dist/memory/relationStore.js.map +1 -0
- package/dist/memory/sessionStore.d.ts +84 -0
- package/dist/memory/sessionStore.d.ts.map +1 -0
- package/dist/memory/sessionStore.js +2 -0
- package/dist/memory/sessionStore.js.map +1 -0
- package/dist/memory/storageInterface.d.ts +107 -0
- package/dist/memory/storageInterface.d.ts.map +1 -0
- package/dist/memory/storageInterface.js +2 -0
- package/dist/memory/storageInterface.js.map +1 -0
- package/dist/memory/store.d.ts +50 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +160 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/memory/types.d.ts +189 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +230 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/memory/userProfile.d.ts +156 -0
- package/dist/memory/userProfile.d.ts.map +1 -0
- package/dist/memory/userProfile.js +315 -0
- package/dist/memory/userProfile.js.map +1 -0
- package/dist/memory/vectorStore.d.ts +75 -0
- package/dist/memory/vectorStore.d.ts.map +1 -0
- package/dist/memory/vectorStore.js +144 -0
- package/dist/memory/vectorStore.js.map +1 -0
- package/dist/persona/personaManager.d.ts +121 -0
- package/dist/persona/personaManager.d.ts.map +1 -0
- package/dist/persona/personaManager.js +349 -0
- package/dist/persona/personaManager.js.map +1 -0
- package/dist/persona/types.d.ts +32 -0
- package/dist/persona/types.d.ts.map +1 -0
- package/dist/persona/types.js +5 -0
- package/dist/persona/types.js.map +1 -0
- package/dist/security/pathGuard.d.ts +121 -0
- package/dist/security/pathGuard.d.ts.map +1 -0
- package/dist/security/pathGuard.js +276 -0
- package/dist/security/pathGuard.js.map +1 -0
- package/dist/skill/skillManager.d.ts +82 -0
- package/dist/skill/skillManager.d.ts.map +1 -0
- package/dist/skill/skillManager.js +198 -0
- package/dist/skill/skillManager.js.map +1 -0
- package/dist/skill/types.d.ts +28 -0
- package/dist/skill/types.d.ts.map +1 -0
- package/dist/skill/types.js +5 -0
- package/dist/skill/types.js.map +1 -0
- package/dist/utils/errors.d.ts +86 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +143 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/eventEmitter.d.ts +87 -0
- package/dist/utils/eventEmitter.d.ts.map +1 -0
- package/dist/utils/eventEmitter.js +79 -0
- package/dist/utils/eventEmitter.js.map +1 -0
- package/dist/utils/frontmatter.d.ts +24 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +44 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/dist/utils/json.d.ts +20 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +65 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/loggerHolder.d.ts +37 -0
- package/dist/utils/loggerHolder.d.ts.map +1 -0
- package/dist/utils/loggerHolder.js +49 -0
- package/dist/utils/loggerHolder.js.map +1 -0
- package/dist/utils/math.d.ts +5 -0
- package/dist/utils/math.d.ts.map +1 -0
- package/dist/utils/math.js +19 -0
- package/dist/utils/math.js.map +1 -0
- package/dist/utils/path.d.ts +28 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +33 -0
- package/dist/utils/path.js.map +1 -0
- package/dist/utils/safeTimer.d.ts +26 -0
- package/dist/utils/safeTimer.d.ts.map +1 -0
- package/dist/utils/safeTimer.js +49 -0
- package/dist/utils/safeTimer.js.map +1 -0
- package/dist/utils/scanner.d.ts +54 -0
- package/dist/utils/scanner.d.ts.map +1 -0
- package/dist/utils/scanner.js +115 -0
- package/dist/utils/scanner.js.map +1 -0
- package/dist/utils/segmenter.d.ts +30 -0
- package/dist/utils/segmenter.d.ts.map +1 -0
- package/dist/utils/segmenter.js +80 -0
- package/dist/utils/segmenter.js.map +1 -0
- package/dist/utils/strings.d.ts +18 -0
- package/dist/utils/strings.d.ts.map +1 -0
- package/dist/utils/strings.js +25 -0
- package/dist/utils/strings.js.map +1 -0
- package/dist/utils/time.d.ts +23 -0
- package/dist/utils/time.d.ts.map +1 -0
- package/dist/utils/time.js +31 -0
- package/dist/utils/time.js.map +1 -0
- package/dist/utils/toError.d.ts +13 -0
- package/dist/utils/toError.d.ts.map +1 -0
- package/dist/utils/toError.js +22 -0
- package/dist/utils/toError.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 技能管理器 — 单层目录扫描 + 关键词匹配
|
|
3
|
+
*
|
|
4
|
+
* 职责:
|
|
5
|
+
* - 启动时扫描 configDir/skills/ 目录
|
|
6
|
+
* - 通过关键词匹配选择技能(初期阶段一/二)
|
|
7
|
+
* - 写入 SQLite 索引(source: skill,遵循"万物皆记忆")
|
|
8
|
+
* - 后期触发条件(≥15个技能 / 关键词命中率 <80%)→ 切换为 LLM 自主选择
|
|
9
|
+
*
|
|
10
|
+
* 设计原则(ADR-004 万物皆记忆):
|
|
11
|
+
* - 技能遵循"万物皆记忆"——存入 SQLite 作为 skill 来源记忆
|
|
12
|
+
* - 单层目录:<configDir>/skills/(宿主负责汇总全局+项目级技能到 configDir)
|
|
13
|
+
* - 与 PersonaManager 存储策略一致:文件加载 → 内存缓存 + SQLite 索引
|
|
14
|
+
*
|
|
15
|
+
* 触发词说明:
|
|
16
|
+
* 每个 skill 文件的 frontmatter 声明 keywords(逗号分隔)和 trigger(触发正则,可选)。
|
|
17
|
+
* skill 文件命名规范:`<技能名>.md`(如"去AI味.md""审视角.md""写代码.md")。
|
|
18
|
+
*/
|
|
19
|
+
import { scoreByKeywords } from '../utils/segmenter.js';
|
|
20
|
+
import { SOURCE_LABELS } from '../memory/types.js';
|
|
21
|
+
import { logger } from '../logging/logger.js';
|
|
22
|
+
import { configError } from '../utils/errors.js';
|
|
23
|
+
import { scanMarkdownDir, parseKeywords, parseTrigger, resolveSubdir } from '../utils/scanner.js';
|
|
24
|
+
/**
|
|
25
|
+
* 技能管理器
|
|
26
|
+
*/
|
|
27
|
+
export class SkillManager {
|
|
28
|
+
configDir;
|
|
29
|
+
index;
|
|
30
|
+
/** 技能列表缓存(启动时扫描一次) */
|
|
31
|
+
skills = [];
|
|
32
|
+
/**
|
|
33
|
+
* @param configDir 配置目录(技能文件在 <configDir>/skills/ 下)
|
|
34
|
+
* @param index SQLite 索引(用于写入 skill 记忆)
|
|
35
|
+
*/
|
|
36
|
+
constructor(configDir, index) {
|
|
37
|
+
this.configDir = configDir;
|
|
38
|
+
this.index = index;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 启动时加载:扫描技能目录
|
|
42
|
+
*
|
|
43
|
+
* @returns 加载的技能数量
|
|
44
|
+
*/
|
|
45
|
+
async load() {
|
|
46
|
+
this.skills = await this.scanSkills();
|
|
47
|
+
logger.info({ count: this.skills.length, names: this.skills.map((s) => s.name) }, '技能加载完成');
|
|
48
|
+
// 写入 SQLite 索引(遵循"万物皆记忆"——与 PersonaManager 一致)
|
|
49
|
+
await this.writeAllToIndex();
|
|
50
|
+
return this.skills.length;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 根据用户输入匹配最合适的技能
|
|
54
|
+
*
|
|
55
|
+
* 匹配流程:
|
|
56
|
+
* 1. 先检查所有 trigger 正则,命中直接返回(最高优先级)
|
|
57
|
+
* 2. 再检查关键词匹配(TF 计分,得分排序)
|
|
58
|
+
* 3. 若匹配多项但得分相同 → 取第一个
|
|
59
|
+
* 4. 无任何匹配 → 返回 null
|
|
60
|
+
*
|
|
61
|
+
* @param userInput 用户输入文本
|
|
62
|
+
* @returns 匹配结果,无匹配返回 null
|
|
63
|
+
*/
|
|
64
|
+
match(userInput) {
|
|
65
|
+
if (this.skills.length === 0)
|
|
66
|
+
return null;
|
|
67
|
+
// 1. trigger 正则匹配(最高优先级)
|
|
68
|
+
for (const skill of this.skills) {
|
|
69
|
+
if (skill.trigger?.test(userInput)) {
|
|
70
|
+
logger.debug({ skill: skill.name, trigger: skill.trigger.source }, '技能触发器匹配');
|
|
71
|
+
return { skill, score: 1.0 };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const matches = [];
|
|
75
|
+
for (const skill of this.skills) {
|
|
76
|
+
if (skill.keywords.length === 0)
|
|
77
|
+
continue;
|
|
78
|
+
const score = scoreByKeywords(userInput, skill.keywords);
|
|
79
|
+
if (score > 0) {
|
|
80
|
+
matches.push({ skill, score });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (matches.length === 0)
|
|
84
|
+
return null;
|
|
85
|
+
// 得分从高到低排序,取第一个
|
|
86
|
+
matches.sort((a, b) => b.score - a.score);
|
|
87
|
+
const best = matches[0];
|
|
88
|
+
if (!best)
|
|
89
|
+
return null;
|
|
90
|
+
logger.debug({ matched: best.skill.name, score: best.score }, '技能关键词匹配');
|
|
91
|
+
return best;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 根据技能名获取技能
|
|
95
|
+
*
|
|
96
|
+
* @param name 技能名
|
|
97
|
+
* @returns 技能条目,不存在返回 null
|
|
98
|
+
*/
|
|
99
|
+
get(name) {
|
|
100
|
+
return this.skills.find((s) => s.name === name) ?? null;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 获取所有技能列表
|
|
104
|
+
*/
|
|
105
|
+
get list() {
|
|
106
|
+
return this.skills;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* 注册运行时注入的技能
|
|
110
|
+
*
|
|
111
|
+
* 供 Agent.addSkill() 调用:宿主程序可在 init() 之后动态注入技能。
|
|
112
|
+
* 重复注册同名技能会被拒绝(与文件加载的技能冲突时也按"先到先得"判断)。
|
|
113
|
+
*
|
|
114
|
+
* @param skill 技能条目
|
|
115
|
+
* @throws 技能名已存在时抛错
|
|
116
|
+
*/
|
|
117
|
+
register(skill) {
|
|
118
|
+
if (this.skills.some((s) => s.name === skill.name)) {
|
|
119
|
+
throw configError(`技能 "${skill.name}" 已存在,不能重复注册`, undefined, ['请使用不同的技能名称']);
|
|
120
|
+
}
|
|
121
|
+
this.skills.push(skill);
|
|
122
|
+
logger.info({ name: skill.name, keywords: skill.keywords.length }, '技能已注册(运行时注入)');
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 构建 system prompt 中的技能段
|
|
126
|
+
*
|
|
127
|
+
* 格式:
|
|
128
|
+
* 【当前技能】技能名
|
|
129
|
+
* 技能 prompt 正文...
|
|
130
|
+
*
|
|
131
|
+
* @param name 技能名(可选,不传返回空)
|
|
132
|
+
*/
|
|
133
|
+
buildSystemPrompt(name) {
|
|
134
|
+
if (!name)
|
|
135
|
+
return '';
|
|
136
|
+
const skill = this.get(name);
|
|
137
|
+
if (!skill)
|
|
138
|
+
return '';
|
|
139
|
+
return `【当前技能】${skill.name}\n${skill.content}`;
|
|
140
|
+
}
|
|
141
|
+
// ── 私有方法 ──────────────────────────────────────
|
|
142
|
+
/**
|
|
143
|
+
* 将所有技能写入 SQLite 索引
|
|
144
|
+
*/
|
|
145
|
+
async writeAllToIndex() {
|
|
146
|
+
if (!this.index)
|
|
147
|
+
return;
|
|
148
|
+
for (const skill of this.skills) {
|
|
149
|
+
this.writeSkillToIndex(skill);
|
|
150
|
+
}
|
|
151
|
+
logger.info({ count: this.skills.length }, '技能记忆已写入 SQLite');
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* 将单个技能写入 SQLite 索引
|
|
155
|
+
*/
|
|
156
|
+
writeSkillToIndex(skill) {
|
|
157
|
+
if (!this.index)
|
|
158
|
+
return;
|
|
159
|
+
const now = new Date().toISOString();
|
|
160
|
+
const memory = {
|
|
161
|
+
id: `skill:${skill.name}`,
|
|
162
|
+
content: skill.content,
|
|
163
|
+
source: SOURCE_LABELS.SKILL,
|
|
164
|
+
name: skill.name,
|
|
165
|
+
createdAt: now,
|
|
166
|
+
accessedAt: now,
|
|
167
|
+
score: 0.7,
|
|
168
|
+
};
|
|
169
|
+
this.index.upsert(memory);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* 扫描 configDir/skills/ 目录
|
|
173
|
+
*
|
|
174
|
+
* 宿主负责将全局+项目级技能汇总到 configDir,
|
|
175
|
+
* 内核只扫描一个目录,不做路径假设。
|
|
176
|
+
*/
|
|
177
|
+
async scanSkills() {
|
|
178
|
+
const map = new Map();
|
|
179
|
+
const skillsDir = resolveSubdir(this.configDir, 'skills');
|
|
180
|
+
if (skillsDir) {
|
|
181
|
+
const entries = await scanMarkdownDir(skillsDir);
|
|
182
|
+
for (const entry of entries) {
|
|
183
|
+
const skill = {
|
|
184
|
+
name: entry.name,
|
|
185
|
+
keywords: parseKeywords(entry.frontmatter),
|
|
186
|
+
trigger: parseTrigger(entry.frontmatter),
|
|
187
|
+
description: entry.frontmatter['description'],
|
|
188
|
+
content: entry.body.trim(),
|
|
189
|
+
filePath: entry.filePath,
|
|
190
|
+
layer: 'project',
|
|
191
|
+
};
|
|
192
|
+
map.set(entry.name, skill);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return Array.from(map.values());
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=skillManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillManager.js","sourceRoot":"","sources":["../../src/skill/skillManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 技能模块类型定义
|
|
3
|
+
*/
|
|
4
|
+
/** 技能条目(从 skills/*.md 解析) */
|
|
5
|
+
export interface SkillEntry {
|
|
6
|
+
/** 技能名(文件名去 .md) */
|
|
7
|
+
name: string;
|
|
8
|
+
/** 触发关键词列表 */
|
|
9
|
+
keywords: string[];
|
|
10
|
+
/** 触发正则(可选,优先级高于 keywords) */
|
|
11
|
+
trigger?: RegExp;
|
|
12
|
+
/** 技能描述(可选) */
|
|
13
|
+
description?: string;
|
|
14
|
+
/** 技能 prompt 正文 */
|
|
15
|
+
content: string;
|
|
16
|
+
/** 来源路径 */
|
|
17
|
+
filePath: string;
|
|
18
|
+
/** 来源层(agent / project) */
|
|
19
|
+
layer: 'agent' | 'project';
|
|
20
|
+
}
|
|
21
|
+
/** 技能匹配结果 */
|
|
22
|
+
export interface SkillMatch {
|
|
23
|
+
/** 匹配的技能 */
|
|
24
|
+
skill: SkillEntry;
|
|
25
|
+
/** 匹配得分(0-1,用于排序) */
|
|
26
|
+
score: number;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/skill/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,6BAA6B;AAC7B,MAAM,WAAW,UAAU;IACzB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,KAAK,EAAE,OAAO,GAAG,SAAS,CAAC;CAC5B;AAED,aAAa;AACb,MAAM,WAAW,UAAU;IACzB,YAAY;IACZ,KAAK,EAAE,UAAU,CAAC;IAClB,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;CACf"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/skill/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export { toError } from '../utils/toError.js';
|
|
2
|
+
export type ErrorCategory = 'config' | 'network' | 'llm' | 'tool' | 'security' | 'unknown';
|
|
3
|
+
/**
|
|
4
|
+
* 工具错误码 — 用于 AgentLoop 的 Reflection(反思/自修正)逻辑
|
|
5
|
+
*
|
|
6
|
+
* 每个错误码关联一个 retryable 标记:
|
|
7
|
+
* - retryable:LLM 可以调整参数后重试(如文件路径错误、参数类型错误)
|
|
8
|
+
* - non-retryable:重试无意义(如权限拒绝、用户拒绝写入)
|
|
9
|
+
*/
|
|
10
|
+
export declare const ToolErrorCode: {
|
|
11
|
+
/** 路径不在白名单内(不可重试) */
|
|
12
|
+
readonly PATH_NOT_ALLOWED: "PATH_NOT_ALLOWED";
|
|
13
|
+
/** 文件不存在(可重试 — LLM 可能用错了路径) */
|
|
14
|
+
readonly FILE_NOT_FOUND: "FILE_NOT_FOUND";
|
|
15
|
+
/** 权限不足(不可重试) */
|
|
16
|
+
readonly PERMISSION_DENIED: "PERMISSION_DENIED";
|
|
17
|
+
/** 工具参数错误(可重试 — LLM 可以修正参数格式) */
|
|
18
|
+
readonly ARGUMENT_ERROR: "ARGUMENT_ERROR";
|
|
19
|
+
/** 工具执行超时(可重试) */
|
|
20
|
+
readonly TOOL_TIMEOUT: "TOOL_TIMEOUT";
|
|
21
|
+
/** 用户拒绝写入(不可重试) */
|
|
22
|
+
readonly WRITE_REJECTED: "WRITE_REJECTED";
|
|
23
|
+
/** 目录不存在(可重试 — LLM 可能用错了路径) */
|
|
24
|
+
readonly DIR_NOT_FOUND: "DIR_NOT_FOUND";
|
|
25
|
+
/** 未知工具(不可重试 — 工具未注册) */
|
|
26
|
+
readonly UNKNOWN_TOOL: "UNKNOWN_TOOL";
|
|
27
|
+
/** 自定义工具执行失败(可重试) */
|
|
28
|
+
readonly CUSTOM_TOOL_FAILED: "CUSTOM_TOOL_FAILED";
|
|
29
|
+
/** 通用错误(不可重试) */
|
|
30
|
+
readonly UNKNOWN: "UNKNOWN";
|
|
31
|
+
};
|
|
32
|
+
export type ToolErrorCodeValue = (typeof ToolErrorCode)[keyof typeof ToolErrorCode];
|
|
33
|
+
export declare function isRetryableErrorCode(code: ToolErrorCodeValue): boolean;
|
|
34
|
+
export interface FriendlyErrorOptions {
|
|
35
|
+
/** 用户能看懂的简短标题(中文) */
|
|
36
|
+
title: string;
|
|
37
|
+
/** 详细原因(可含原文) */
|
|
38
|
+
detail?: string;
|
|
39
|
+
/** 下一步建议(数组,按优先级) */
|
|
40
|
+
suggestions: string[];
|
|
41
|
+
/** 错误分类 */
|
|
42
|
+
category: ErrorCategory;
|
|
43
|
+
/** 工具错误码(用于 AgentLoop Reflection 判断是否可重试) */
|
|
44
|
+
errorCode?: ToolErrorCodeValue;
|
|
45
|
+
/** 原始错误(保留 stack) */
|
|
46
|
+
cause?: Error;
|
|
47
|
+
}
|
|
48
|
+
export declare class MemoraError extends Error {
|
|
49
|
+
readonly title: string;
|
|
50
|
+
readonly detail: string | undefined;
|
|
51
|
+
readonly suggestions: readonly string[];
|
|
52
|
+
readonly category: ErrorCategory;
|
|
53
|
+
/** 工具错误码(用于 AgentLoop 反思判断是否可重试) */
|
|
54
|
+
readonly errorCode: ToolErrorCodeValue | undefined;
|
|
55
|
+
readonly cause: Error | undefined;
|
|
56
|
+
constructor(opts: FriendlyErrorOptions);
|
|
57
|
+
/**
|
|
58
|
+
* 格式化为用户可读的展示字符串
|
|
59
|
+
*/
|
|
60
|
+
format(): string;
|
|
61
|
+
/**
|
|
62
|
+
* 记录到日志(结构化)
|
|
63
|
+
*/
|
|
64
|
+
log(): void;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 工厂:配置错误
|
|
68
|
+
*/
|
|
69
|
+
export declare function configError(title: string, detail: string | undefined, suggestions: string[], cause?: Error): MemoraError;
|
|
70
|
+
/**
|
|
71
|
+
* 工厂:网络错误
|
|
72
|
+
*/
|
|
73
|
+
export declare function networkError(title: string, detail: string | undefined, suggestions: string[], cause?: Error): MemoraError;
|
|
74
|
+
/**
|
|
75
|
+
* 工厂:LLM 错误
|
|
76
|
+
*/
|
|
77
|
+
export declare function llmError(title: string, detail: string | undefined, suggestions: string[], cause?: Error): MemoraError;
|
|
78
|
+
/**
|
|
79
|
+
* 工厂:工具错误
|
|
80
|
+
*/
|
|
81
|
+
export declare function toolError(title: string, detail: string | undefined, suggestions: string[], cause?: Error, errorCode?: ToolErrorCodeValue): MemoraError;
|
|
82
|
+
/**
|
|
83
|
+
* 工厂:安全错误(路径越界、黑名单命中、权限不足等)
|
|
84
|
+
*/
|
|
85
|
+
export declare function securityError(title: string, detail: string | undefined, suggestions: string[], cause?: Error): MemoraError;
|
|
86
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;AAE3F;;;;;;GAMG;AACH,eAAO,MAAM,aAAa;IACxB,qBAAqB;;IAErB,+BAA+B;;IAE/B,iBAAiB;;IAEjB,iCAAiC;;IAEjC,kBAAkB;;IAElB,mBAAmB;;IAEnB,+BAA+B;;IAE/B,yBAAyB;;IAEzB,qBAAqB;;IAErB,iBAAiB;;CAET,CAAC;AAEX,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC;AAapF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAEtE;AAED,MAAM,WAAW,oBAAoB;IACnC,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW;IACX,QAAQ,EAAE,aAAa,CAAC;IACxB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,qBAAqB;IACrB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,oCAAoC;IACpC,QAAQ,CAAC,SAAS,EAAE,kBAAkB,GAAG,SAAS,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;gBAEtB,IAAI,EAAE,oBAAoB;IAWtC;;OAEG;IACH,MAAM,IAAI,MAAM;IAahB;;OAEG;IACH,GAAG,IAAI,IAAI;CAcZ;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,WAAW,EAAE,MAAM,EAAE,EACrB,KAAK,CAAC,EAAE,KAAK,GACZ,WAAW,CAEb;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,WAAW,EAAE,MAAM,EAAE,EACrB,KAAK,CAAC,EAAE,KAAK,GACZ,WAAW,CAEb;AAED;;GAEG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,WAAW,EAAE,MAAM,EAAE,EACrB,KAAK,CAAC,EAAE,KAAK,GACZ,WAAW,CAEb;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,WAAW,EAAE,MAAM,EAAE,EACrB,KAAK,CAAC,EAAE,KAAK,EACb,SAAS,CAAC,EAAE,kBAAkB,GAC7B,WAAW,CAEb;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,WAAW,EAAE,MAAM,EAAE,EACrB,KAAK,CAAC,EAAE,KAAK,GACZ,WAAW,CAEb"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 统一错误类型
|
|
3
|
+
*
|
|
4
|
+
* 把"系统 Error + 英文 stack trace"包装成"分类清晰 + 中文友好 + 有下一步建议"的错误
|
|
5
|
+
* 详见 ADR-006 · 安全模型
|
|
6
|
+
*
|
|
7
|
+
* 4 大类:
|
|
8
|
+
* - ConfigError 配置错误(apiKey 缺失、provider 不支持等)
|
|
9
|
+
* - NetworkError 网络错误(连接超时、DNS 失败、限流等)
|
|
10
|
+
* - LlmError LLM 错误(4xx/5xx、返回异常 JSON)
|
|
11
|
+
* - ToolError 工具错误(路径越界、参数无效等)
|
|
12
|
+
*
|
|
13
|
+
* 错误展示原则:
|
|
14
|
+
* 1. 标题(中文)—— 一眼看出什么问题
|
|
15
|
+
* 2. 详情(原文)—— 排查用
|
|
16
|
+
* 3. 建议(下一步)—— 怎么修复
|
|
17
|
+
*/
|
|
18
|
+
import { getLogger } from '../utils/loggerHolder.js';
|
|
19
|
+
// 纯逻辑 toError,浏览器端可直接 import 此文件而不引入 logger 依赖
|
|
20
|
+
export { toError } from '../utils/toError.js';
|
|
21
|
+
/**
|
|
22
|
+
* 工具错误码 — 用于 AgentLoop 的 Reflection(反思/自修正)逻辑
|
|
23
|
+
*
|
|
24
|
+
* 每个错误码关联一个 retryable 标记:
|
|
25
|
+
* - retryable:LLM 可以调整参数后重试(如文件路径错误、参数类型错误)
|
|
26
|
+
* - non-retryable:重试无意义(如权限拒绝、用户拒绝写入)
|
|
27
|
+
*/
|
|
28
|
+
export const ToolErrorCode = {
|
|
29
|
+
/** 路径不在白名单内(不可重试) */
|
|
30
|
+
PATH_NOT_ALLOWED: 'PATH_NOT_ALLOWED',
|
|
31
|
+
/** 文件不存在(可重试 — LLM 可能用错了路径) */
|
|
32
|
+
FILE_NOT_FOUND: 'FILE_NOT_FOUND',
|
|
33
|
+
/** 权限不足(不可重试) */
|
|
34
|
+
PERMISSION_DENIED: 'PERMISSION_DENIED',
|
|
35
|
+
/** 工具参数错误(可重试 — LLM 可以修正参数格式) */
|
|
36
|
+
ARGUMENT_ERROR: 'ARGUMENT_ERROR',
|
|
37
|
+
/** 工具执行超时(可重试) */
|
|
38
|
+
TOOL_TIMEOUT: 'TOOL_TIMEOUT',
|
|
39
|
+
/** 用户拒绝写入(不可重试) */
|
|
40
|
+
WRITE_REJECTED: 'WRITE_REJECTED',
|
|
41
|
+
/** 目录不存在(可重试 — LLM 可能用错了路径) */
|
|
42
|
+
DIR_NOT_FOUND: 'DIR_NOT_FOUND',
|
|
43
|
+
/** 未知工具(不可重试 — 工具未注册) */
|
|
44
|
+
UNKNOWN_TOOL: 'UNKNOWN_TOOL',
|
|
45
|
+
/** 自定义工具执行失败(可重试) */
|
|
46
|
+
CUSTOM_TOOL_FAILED: 'CUSTOM_TOOL_FAILED',
|
|
47
|
+
/** 通用错误(不可重试) */
|
|
48
|
+
UNKNOWN: 'UNKNOWN',
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* 判断错误码是否可重试
|
|
52
|
+
*/
|
|
53
|
+
const RETRYABLE_ERROR_CODES = new Set([
|
|
54
|
+
ToolErrorCode.FILE_NOT_FOUND,
|
|
55
|
+
ToolErrorCode.ARGUMENT_ERROR,
|
|
56
|
+
ToolErrorCode.TOOL_TIMEOUT,
|
|
57
|
+
ToolErrorCode.DIR_NOT_FOUND,
|
|
58
|
+
ToolErrorCode.CUSTOM_TOOL_FAILED,
|
|
59
|
+
]);
|
|
60
|
+
export function isRetryableErrorCode(code) {
|
|
61
|
+
return RETRYABLE_ERROR_CODES.has(code);
|
|
62
|
+
}
|
|
63
|
+
export class MemoraError extends Error {
|
|
64
|
+
title;
|
|
65
|
+
detail;
|
|
66
|
+
suggestions;
|
|
67
|
+
category;
|
|
68
|
+
/** 工具错误码(用于 AgentLoop 反思判断是否可重试) */
|
|
69
|
+
errorCode;
|
|
70
|
+
cause;
|
|
71
|
+
constructor(opts) {
|
|
72
|
+
super(opts.title);
|
|
73
|
+
this.name = 'MemoraError';
|
|
74
|
+
this.title = opts.title;
|
|
75
|
+
this.detail = opts.detail;
|
|
76
|
+
this.suggestions = Object.freeze(opts.suggestions);
|
|
77
|
+
this.category = opts.category;
|
|
78
|
+
this.errorCode = opts.errorCode;
|
|
79
|
+
this.cause = opts.cause;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 格式化为用户可读的展示字符串
|
|
83
|
+
*/
|
|
84
|
+
format() {
|
|
85
|
+
const lines = [];
|
|
86
|
+
lines.push(`❌ ${this.title}`);
|
|
87
|
+
if (this.detail)
|
|
88
|
+
lines.push(` 原因:${this.detail}`);
|
|
89
|
+
if (this.suggestions.length > 0) {
|
|
90
|
+
lines.push(` 建议:`);
|
|
91
|
+
for (const s of this.suggestions) {
|
|
92
|
+
lines.push(` - ${s}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return lines.join('\n');
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* 记录到日志(结构化)
|
|
99
|
+
*/
|
|
100
|
+
log() {
|
|
101
|
+
getLogger().error({
|
|
102
|
+
err: this,
|
|
103
|
+
category: this.category,
|
|
104
|
+
title: this.title,
|
|
105
|
+
detail: this.detail,
|
|
106
|
+
suggestions: this.suggestions,
|
|
107
|
+
cause: this.cause?.message,
|
|
108
|
+
stack: this.stack,
|
|
109
|
+
}, this.title);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* 工厂:配置错误
|
|
114
|
+
*/
|
|
115
|
+
export function configError(title, detail, suggestions, cause) {
|
|
116
|
+
return new MemoraError({ title, detail, suggestions, category: 'config', cause });
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 工厂:网络错误
|
|
120
|
+
*/
|
|
121
|
+
export function networkError(title, detail, suggestions, cause) {
|
|
122
|
+
return new MemoraError({ title, detail, suggestions, category: 'network', cause });
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 工厂:LLM 错误
|
|
126
|
+
*/
|
|
127
|
+
export function llmError(title, detail, suggestions, cause) {
|
|
128
|
+
return new MemoraError({ title, detail, suggestions, category: 'llm', cause });
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* 工厂:工具错误
|
|
132
|
+
*/
|
|
133
|
+
export function toolError(title, detail, suggestions, cause, errorCode) {
|
|
134
|
+
return new MemoraError({ title, detail, suggestions, category: 'tool', cause, errorCode });
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* 工厂:安全错误(路径越界、黑名单命中、权限不足等)
|
|
138
|
+
*/
|
|
139
|
+
export function securityError(title, detail, suggestions, cause) {
|
|
140
|
+
return new MemoraError({ title, detail, suggestions, category: 'security', cause });
|
|
141
|
+
}
|
|
142
|
+
// toError 已移至 ./toError.ts(纯逻辑,零依赖),此处 re-export 保持向后兼容
|
|
143
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/** Agent 事件映射表(事件名 → 事件载荷类型) */
|
|
2
|
+
export interface AgentEventMap {
|
|
3
|
+
/** 记忆被写入存储(insight 提取、rule 注入、skill 注入等) */
|
|
4
|
+
memoryAdded: {
|
|
5
|
+
id: string;
|
|
6
|
+
source: string;
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
/** 角色被切换(自动匹配或手动指定) */
|
|
10
|
+
personaSwitched: {
|
|
11
|
+
from: string | null;
|
|
12
|
+
to: string;
|
|
13
|
+
};
|
|
14
|
+
/** 记忆衰减完成 */
|
|
15
|
+
decayCompleted: {
|
|
16
|
+
decayedCount: number;
|
|
17
|
+
};
|
|
18
|
+
/** 记忆被召回(用于宿主 UI 展示"想起 X 条记忆") */
|
|
19
|
+
memoryRecalled: {
|
|
20
|
+
count: number;
|
|
21
|
+
query: string;
|
|
22
|
+
};
|
|
23
|
+
/** 会话被分叉 */
|
|
24
|
+
sessionForked: {
|
|
25
|
+
from: string;
|
|
26
|
+
to: string;
|
|
27
|
+
messageCount: number;
|
|
28
|
+
};
|
|
29
|
+
/** 洞察被提取 */
|
|
30
|
+
insightExtracted: {
|
|
31
|
+
source: string;
|
|
32
|
+
insight: string;
|
|
33
|
+
};
|
|
34
|
+
/** 项目被切换(A-003:宿主 UI 可据此刷新项目相关界面) */
|
|
35
|
+
projectSwitched: {
|
|
36
|
+
from: string | null;
|
|
37
|
+
to: string;
|
|
38
|
+
projectName: string;
|
|
39
|
+
};
|
|
40
|
+
/** 技能被匹配(A-003:宿主 UI 可据此展示当前激活技能) */
|
|
41
|
+
skillMatched: {
|
|
42
|
+
skill: string;
|
|
43
|
+
score: number;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** 事件名联合类型 */
|
|
47
|
+
export type AgentEventName = keyof AgentEventMap;
|
|
48
|
+
/** 事件处理器类型 */
|
|
49
|
+
export type AgentEventHandler<T> = (event: T) => void;
|
|
50
|
+
/**
|
|
51
|
+
* 类型安全的事件发射器
|
|
52
|
+
*
|
|
53
|
+
* 泛型参数 EventMap 约束了合法的事件名和对应的载荷类型,
|
|
54
|
+
* 调用方在编译期就能获得类型检查和自动补全。
|
|
55
|
+
*/
|
|
56
|
+
export declare class TypedEventEmitter<EventMap extends object> {
|
|
57
|
+
private readonly listeners;
|
|
58
|
+
/**
|
|
59
|
+
* 订阅事件
|
|
60
|
+
* @param event - 事件名
|
|
61
|
+
* @param handler - 事件处理器
|
|
62
|
+
*/
|
|
63
|
+
on<K extends keyof EventMap & string>(event: K, handler: (event: EventMap[K]) => void): void;
|
|
64
|
+
/**
|
|
65
|
+
* 取消订阅
|
|
66
|
+
* @param event - 事件名
|
|
67
|
+
* @param handler - 要移除的处理器(必须是同一个引用)
|
|
68
|
+
*/
|
|
69
|
+
off<K extends keyof EventMap & string>(event: K, handler: (event: EventMap[K]) => void): void;
|
|
70
|
+
/**
|
|
71
|
+
* 订阅事件(仅触发一次,触发后自动移除)
|
|
72
|
+
* @param event - 事件名
|
|
73
|
+
* @param handler - 事件处理器
|
|
74
|
+
*/
|
|
75
|
+
once<K extends keyof EventMap & string>(event: K, handler: (event: EventMap[K]) => void): void;
|
|
76
|
+
/**
|
|
77
|
+
* 发射事件
|
|
78
|
+
* @param event - 事件名
|
|
79
|
+
* @param payload - 事件载荷
|
|
80
|
+
*/
|
|
81
|
+
protected emit<K extends keyof EventMap & string>(event: K, payload: EventMap[K]): void;
|
|
82
|
+
/**
|
|
83
|
+
* 移除所有监听器(用于 close() 清理)
|
|
84
|
+
*/
|
|
85
|
+
protected removeAllListeners(): void;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=eventEmitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eventEmitter.d.ts","sourceRoot":"","sources":["../../src/utils/eventEmitter.ts"],"names":[],"mappings":"AAaA,gCAAgC;AAChC,MAAM,WAAW,aAAa;IAC5B,4CAA4C;IAC5C,WAAW,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1D,uBAAuB;IACvB,eAAe,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,aAAa;IACb,cAAc,EAAE;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,kCAAkC;IAClC,cAAc,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,YAAY;IACZ,aAAa,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IAClE,YAAY;IACZ,gBAAgB,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,qCAAqC;IACrC,eAAe,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1E,qCAAqC;IACrC,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAChD;AAED,cAAc;AACd,MAAM,MAAM,cAAc,GAAG,MAAM,aAAa,CAAC;AAEjD,cAAc;AACd,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;AAEtD;;;;;GAKG;AACH,qBAAa,iBAAiB,CAAC,QAAQ,SAAS,MAAM;IACpD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoD;IAE9E;;;;OAIG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,QAAQ,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI;IAS5F;;;;OAIG;IACH,GAAG,CAAC,CAAC,SAAS,MAAM,QAAQ,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI;IAI7F;;;;OAIG;IACH,IAAI,CAAC,CAAC,SAAS,MAAM,QAAQ,GAAG,MAAM,EACpC,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,GACpC,IAAI;IAQP;;;;OAIG;IACH,SAAS,CAAC,IAAI,CAAC,CAAC,SAAS,MAAM,QAAQ,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI;IAYvF;;OAEG;IACH,SAAS,CAAC,kBAAkB,IAAI,IAAI;CAGrC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 轻量类型事件发射器 — 零外部依赖
|
|
3
|
+
*
|
|
4
|
+
* 供 Agent 向宿主项目广播对话外事件(记忆变更、角色切换、衰减完成等)。
|
|
5
|
+
* 不依赖 Node.js EventEmitter,保持"零 native 依赖内核"约束。
|
|
6
|
+
*
|
|
7
|
+
* 使用方式:
|
|
8
|
+
* agent.on('memoryAdded', (e) => console.log(e.source, e.name));
|
|
9
|
+
* agent.off('memoryAdded', handler);
|
|
10
|
+
*/
|
|
11
|
+
import { getLogger } from '../utils/loggerHolder.js';
|
|
12
|
+
import { toError } from '../utils/errors.js';
|
|
13
|
+
/**
|
|
14
|
+
* 类型安全的事件发射器
|
|
15
|
+
*
|
|
16
|
+
* 泛型参数 EventMap 约束了合法的事件名和对应的载荷类型,
|
|
17
|
+
* 调用方在编译期就能获得类型检查和自动补全。
|
|
18
|
+
*/
|
|
19
|
+
export class TypedEventEmitter {
|
|
20
|
+
listeners = new Map();
|
|
21
|
+
/**
|
|
22
|
+
* 订阅事件
|
|
23
|
+
* @param event - 事件名
|
|
24
|
+
* @param handler - 事件处理器
|
|
25
|
+
*/
|
|
26
|
+
on(event, handler) {
|
|
27
|
+
let set = this.listeners.get(event);
|
|
28
|
+
if (!set) {
|
|
29
|
+
set = new Set();
|
|
30
|
+
this.listeners.set(event, set);
|
|
31
|
+
}
|
|
32
|
+
set.add(handler);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 取消订阅
|
|
36
|
+
* @param event - 事件名
|
|
37
|
+
* @param handler - 要移除的处理器(必须是同一个引用)
|
|
38
|
+
*/
|
|
39
|
+
off(event, handler) {
|
|
40
|
+
this.listeners.get(event)?.delete(handler);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 订阅事件(仅触发一次,触发后自动移除)
|
|
44
|
+
* @param event - 事件名
|
|
45
|
+
* @param handler - 事件处理器
|
|
46
|
+
*/
|
|
47
|
+
once(event, handler) {
|
|
48
|
+
const wrapper = ((data) => {
|
|
49
|
+
this.off(event, wrapper);
|
|
50
|
+
handler(data);
|
|
51
|
+
});
|
|
52
|
+
this.on(event, wrapper);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 发射事件
|
|
56
|
+
* @param event - 事件名
|
|
57
|
+
* @param payload - 事件载荷
|
|
58
|
+
*/
|
|
59
|
+
emit(event, payload) {
|
|
60
|
+
const set = this.listeners.get(event);
|
|
61
|
+
if (!set || set.size === 0)
|
|
62
|
+
return;
|
|
63
|
+
for (const handler of set) {
|
|
64
|
+
try {
|
|
65
|
+
handler(payload);
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
getLogger().warn({ event, err: toError(err).message }, '宿主事件处理器异常');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 移除所有监听器(用于 close() 清理)
|
|
74
|
+
*/
|
|
75
|
+
removeAllListeners() {
|
|
76
|
+
this.listeners.clear();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=eventEmitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eventEmitter.js","sourceRoot":"","sources":["../../src/utils/eventEmitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AA4B5C;;;;;GAKG;AACH,MAAM,OAAO,iBAAiB;IACX,SAAS,GAAG,IAAI,GAAG,EAAyC,CAAC;IAE9E;;;;OAIG;IACH,EAAE,CAAoC,KAAQ,EAAE,OAAqC;QACnF,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;YAChB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACjC,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,OAAmC,CAAC,CAAC;IAC/C,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAoC,KAAQ,EAAE,OAAqC;QACpF,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,OAAmC,CAAC,CAAC;IACzE,CAAC;IAED;;;;OAIG;IACH,IAAI,CACF,KAAQ,EACR,OAAqC;QAErC,MAAM,OAAO,GAAG,CAAC,CAAC,IAAiB,EAAE,EAAE;YACrC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,OAAuC,CAAC,CAAC;YACzD,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC,CAAiC,CAAC;QACnC,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC1B,CAAC;IAED;;;;OAIG;IACO,IAAI,CAAoC,KAAQ,EAAE,OAAoB;QAC9E,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO;QACnC,KAAK,MAAM,OAAO,IAAI,GAAG,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACH,OAAO,CAAC,OAAO,CAAC,CAAC;YACnB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;YACtE,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACO,kBAAkB;QAC1B,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;CACF"}
|