@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,288 @@
|
|
|
1
|
+
import { logger } from '../logging/logger.js';
|
|
2
|
+
import { configError } from '../utils/errors.js';
|
|
3
|
+
import { nowIso, todayDate } from '../utils/time.js';
|
|
4
|
+
/**
|
|
5
|
+
* 消息历史类
|
|
6
|
+
*/
|
|
7
|
+
export class MessageHistory {
|
|
8
|
+
sessionStore;
|
|
9
|
+
minWindowRounds;
|
|
10
|
+
/** 当前日期 YYYY-MM-DD */
|
|
11
|
+
currentDate;
|
|
12
|
+
/** 当前会话标识(不含日期前缀) */
|
|
13
|
+
currentSession;
|
|
14
|
+
/**
|
|
15
|
+
* 挂起的归档企划集合,Agent.close() 等待它们完成
|
|
16
|
+
* 容纳 Promise<void>(fire-and-forget 内部)
|
|
17
|
+
*/
|
|
18
|
+
pendingArchives = new Set();
|
|
19
|
+
constructor(
|
|
20
|
+
/**
|
|
21
|
+
* 会话存储(可选)
|
|
22
|
+
* 注入后,消息会持久化到宿主提供的存储实现。
|
|
23
|
+
* 不注入则仅在内存中保存(AgentLoop.messages[])。
|
|
24
|
+
*/
|
|
25
|
+
sessionStore,
|
|
26
|
+
/**
|
|
27
|
+
* 临时记忆最小窗口轮次(记忆减法方案 v1.0 · 排雷修正 L2)
|
|
28
|
+
*
|
|
29
|
+
* 上下文压缩时,最少保留的对话轮次。即使上下文利用率 ≥ 85%,
|
|
30
|
+
* 也不压缩到少于此轮次,保证基本上下文连贯性。
|
|
31
|
+
* 默认 3 轮,不可在运行时突破。
|
|
32
|
+
*/
|
|
33
|
+
minWindowRounds = 3, initialDate, initialSession = 'main') {
|
|
34
|
+
this.sessionStore = sessionStore;
|
|
35
|
+
this.minWindowRounds = minWindowRounds;
|
|
36
|
+
this.currentDate = initialDate ?? todayDate();
|
|
37
|
+
this.currentSession = initialSession;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 获取当前会话名(日期-会话组合名)
|
|
41
|
+
*/
|
|
42
|
+
get currentSessionName() {
|
|
43
|
+
return `${this.currentDate}-${this.currentSession}`;
|
|
44
|
+
}
|
|
45
|
+
/** 获取当前日期 YYYY-MM-DD(只读,供 agent 层使用) */
|
|
46
|
+
get currentDateValue() {
|
|
47
|
+
return this.currentDate;
|
|
48
|
+
}
|
|
49
|
+
/** 获取当前会话标识(只读,供 agent 层使用) */
|
|
50
|
+
get currentSessionValue() {
|
|
51
|
+
return this.currentSession;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 获取当前会话标识
|
|
55
|
+
*/
|
|
56
|
+
get session() {
|
|
57
|
+
return this.currentSession;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 获取最小窗口轮次(记忆减法方案 v1.0)
|
|
61
|
+
* 上下文压缩时的下限保护
|
|
62
|
+
*/
|
|
63
|
+
get minWindowRoundsValue() {
|
|
64
|
+
return this.minWindowRounds;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 切换会话
|
|
68
|
+
* @param newSession - 新会话标识
|
|
69
|
+
* @returns 新会话的全名
|
|
70
|
+
*/
|
|
71
|
+
switchSession(newSession) {
|
|
72
|
+
this.currentSession = newSession;
|
|
73
|
+
return this.currentSessionName;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 自动生成分支名
|
|
77
|
+
*
|
|
78
|
+
* 算法:扫描已存在会话,找到以 sourceSession-b 为前缀的最大序号,+1
|
|
79
|
+
*
|
|
80
|
+
* @param sourceSession - 源会话标识
|
|
81
|
+
* @returns 自动生成的分支名(如 "main-b1")
|
|
82
|
+
*/
|
|
83
|
+
autoBranchName(sourceSession) {
|
|
84
|
+
if (!this.sessionStore)
|
|
85
|
+
return `${sourceSession}-b1`;
|
|
86
|
+
const allSessions = this.sessionStore.listSessions();
|
|
87
|
+
const prefix = `${sourceSession}-b`;
|
|
88
|
+
// 提取匹配前缀的序号
|
|
89
|
+
const existingNumbers = [];
|
|
90
|
+
for (const fullSession of allSessions) {
|
|
91
|
+
// fullSession 格式:YYYY-MM-DD-session
|
|
92
|
+
const parts = fullSession.split('-');
|
|
93
|
+
if (parts.length >= 4) {
|
|
94
|
+
const sessionPart = parts.slice(3).join('-');
|
|
95
|
+
if (sessionPart.startsWith(prefix)) {
|
|
96
|
+
const numStr = sessionPart.slice(prefix.length);
|
|
97
|
+
const num = parseInt(numStr, 10);
|
|
98
|
+
if (!isNaN(num)) {
|
|
99
|
+
existingNumbers.push(num);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const nextNumber = existingNumbers.length > 0 ? Math.max(...existingNumbers) + 1 : 1;
|
|
105
|
+
return `${prefix}${nextNumber}`;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 分叉当前会话
|
|
109
|
+
*
|
|
110
|
+
* 流程:
|
|
111
|
+
* 1. 从 sessionStore 加载当前会话全部消息
|
|
112
|
+
* 2. 生成唯一新会话名
|
|
113
|
+
* 3. 通过 sessionStore.copySession() 复制到新会话
|
|
114
|
+
* 4. switchSession() 切换当前会话标识到新会话
|
|
115
|
+
*
|
|
116
|
+
* @param targetSession - 自定义目标会话名(可选,不传则自动生成)
|
|
117
|
+
* @returns 分叉结果
|
|
118
|
+
* @throws 若 sessionStore 未注入、copySession 未实现或当前会话无消息
|
|
119
|
+
*/
|
|
120
|
+
forkSession(targetSession) {
|
|
121
|
+
if (!this.sessionStore) {
|
|
122
|
+
throw configError('无法分叉会话', 'ISessionStore 未注入', [
|
|
123
|
+
'在创建 Agent 时注入 sessionStore 参数',
|
|
124
|
+
]);
|
|
125
|
+
}
|
|
126
|
+
if (!this.sessionStore.copySession) {
|
|
127
|
+
throw configError('无法分叉会话', 'ISessionStore.copySession 未实现', [
|
|
128
|
+
'升级宿主项目的 ISessionStore 实现,添加 copySession() 方法',
|
|
129
|
+
]);
|
|
130
|
+
}
|
|
131
|
+
const sourceDate = this.currentDate;
|
|
132
|
+
const sourceSession = this.currentSession;
|
|
133
|
+
// 加载源会话消息
|
|
134
|
+
const messages = this.sessionStore.loadMessages(sourceDate, sourceSession);
|
|
135
|
+
if (messages.length === 0) {
|
|
136
|
+
throw configError('无法分叉会话', '当前会话无消息', ['先进行一些对话后再尝试分叉']);
|
|
137
|
+
}
|
|
138
|
+
// 生成目标会话名
|
|
139
|
+
let newSession;
|
|
140
|
+
if (targetSession) {
|
|
141
|
+
// 检查目标会话在当天是否已存在
|
|
142
|
+
const targetFullName = `${todayDate()}-${targetSession}`;
|
|
143
|
+
const existingSessions = this.sessionStore.listSessions();
|
|
144
|
+
if (existingSessions.includes(targetFullName)) {
|
|
145
|
+
throw configError('无法分叉会话', `当天会话 "${targetSession}" 已存在`, [
|
|
146
|
+
'使用不同的名称,或不传参数自动生成',
|
|
147
|
+
]);
|
|
148
|
+
}
|
|
149
|
+
newSession = targetSession;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
newSession = this.autoBranchName(sourceSession);
|
|
153
|
+
}
|
|
154
|
+
// 计算目标日期
|
|
155
|
+
const targetDate = todayDate();
|
|
156
|
+
// 原子复制消息
|
|
157
|
+
this.sessionStore.copySession(sourceDate, sourceSession, targetDate, newSession);
|
|
158
|
+
// 切换当前会话到新分支
|
|
159
|
+
this.switchSession(newSession);
|
|
160
|
+
logger.info({ from: sourceSession, to: newSession, messageCount: messages.length }, '会话分叉完成');
|
|
161
|
+
return { newSession, date: targetDate, messages };
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* 追加 user 消息到当前会话
|
|
165
|
+
* 失败不抛出(消息持久化失败不应阻塞对话)
|
|
166
|
+
*
|
|
167
|
+
* 日期使用 todayDate() 动态获取,而非缓存的 this.currentDate,
|
|
168
|
+
* 确保跨日后消息写入当天目录。
|
|
169
|
+
*/
|
|
170
|
+
async appendUser(content) {
|
|
171
|
+
const message = {
|
|
172
|
+
role: 'user',
|
|
173
|
+
content,
|
|
174
|
+
timestamp: nowIso(),
|
|
175
|
+
};
|
|
176
|
+
// 使用 ISessionStore 持久化(如果已注入)
|
|
177
|
+
if (this.sessionStore) {
|
|
178
|
+
try {
|
|
179
|
+
// 动态获取当天日期,避免跨日后写入旧日期目录
|
|
180
|
+
this.sessionStore.appendMessage(todayDate(), this.currentSession, message);
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
logger.warn({ err, session: this.currentSessionName }, 'appendUser: 会话持久化失败');
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
logger.debug({ role: message.role, session: this.currentSessionName }, 'appendUser');
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* 追加 assistant 消息到当前会话
|
|
190
|
+
* 失败不抛出
|
|
191
|
+
*
|
|
192
|
+
* 日期使用 todayDate() 动态获取,确保跨日后消息写入当天目录。
|
|
193
|
+
*/
|
|
194
|
+
async appendAssistant(content) {
|
|
195
|
+
if (!content.trim())
|
|
196
|
+
return;
|
|
197
|
+
const message = {
|
|
198
|
+
role: 'assistant',
|
|
199
|
+
content,
|
|
200
|
+
timestamp: nowIso(),
|
|
201
|
+
};
|
|
202
|
+
// 使用 ISessionStore 持久化(如果已注入)
|
|
203
|
+
if (this.sessionStore) {
|
|
204
|
+
try {
|
|
205
|
+
// 动态获取当天日期,避免跨日后写入旧日期目录
|
|
206
|
+
this.sessionStore.appendMessage(todayDate(), this.currentSession, message);
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
logger.warn({ err, session: this.currentSessionName }, 'appendAssistant: 会话持久化失败');
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
logger.debug({ role: message.role, session: this.currentSessionName }, 'appendAssistant');
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* 列出所有会话标识
|
|
216
|
+
*
|
|
217
|
+
* @returns 会话标识列表(格式:YYYY-MM-DD-session),未注入 ISessionStore 则返回空
|
|
218
|
+
*/
|
|
219
|
+
async listAllSessions() {
|
|
220
|
+
if (!this.sessionStore) {
|
|
221
|
+
logger.debug({ hasSessionStore: false }, 'listAllSessions: ISessionStore 未注入,返回空数组');
|
|
222
|
+
return [];
|
|
223
|
+
}
|
|
224
|
+
return this.sessionStore.listSessions();
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* 从会话存储恢复历史消息
|
|
228
|
+
* 用于重启后恢复之前的对话
|
|
229
|
+
*
|
|
230
|
+
* @param date - 会话日期 YYYY-MM-DD
|
|
231
|
+
* @param session - 会话标识
|
|
232
|
+
* @returns 会话中的消息列表,未注入 ISessionStore 则返回空数组
|
|
233
|
+
*/
|
|
234
|
+
async loadSessionMessages(date, session) {
|
|
235
|
+
// 更新当前会话为请求的会话(保持状态一致)
|
|
236
|
+
this.currentDate = date;
|
|
237
|
+
this.currentSession = session;
|
|
238
|
+
if (!this.sessionStore) {
|
|
239
|
+
logger.debug({ date, session }, 'loadSessionMessages: ISessionStore 未注入,返回空数组');
|
|
240
|
+
return [];
|
|
241
|
+
}
|
|
242
|
+
const messages = this.sessionStore.loadMessages(date, session);
|
|
243
|
+
logger.info({ date, session, count: messages.length }, 'loadSessionMessages');
|
|
244
|
+
return messages;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* 把外部 fire-and-forget 归档注册到 pendingArchives
|
|
248
|
+
* 供 Agent.chat() 触发 signal 归档时使用
|
|
249
|
+
*/
|
|
250
|
+
registerPendingArchive(p) {
|
|
251
|
+
this.pendingArchives.add(p);
|
|
252
|
+
p.finally(() => {
|
|
253
|
+
this.pendingArchives.delete(p);
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* 等待所有挂起的归档完成(Agent.close() 时调用)
|
|
258
|
+
* 防止 fire-and-forget 还在写 SQLite 时 db 已被 close
|
|
259
|
+
*
|
|
260
|
+
* 重要:会捕获**等待期间新加入**的归档(解决 init() → archiveMissingSessions() 的 race)
|
|
261
|
+
* 实现:用 50ms 间隔轮询检查新加入的 promise,直到所有归档完成或超时
|
|
262
|
+
*
|
|
263
|
+
* @param timeoutMs 单次等待超时(默认 5000ms)
|
|
264
|
+
* @returns 是否所有归档都完成(false 表示有超时)
|
|
265
|
+
*/
|
|
266
|
+
async awaitPendingArchives(timeoutMs = 5000) {
|
|
267
|
+
// 快速路径:无挂起任务时立即返回(避免空轮询浪费 5s)
|
|
268
|
+
if (this.pendingArchives.size === 0)
|
|
269
|
+
return true;
|
|
270
|
+
const deadline = Date.now() + timeoutMs;
|
|
271
|
+
while (Date.now() < deadline) {
|
|
272
|
+
const current = Array.from(this.pendingArchives);
|
|
273
|
+
if (current.length === 0) {
|
|
274
|
+
// 所有归档已完成
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
// 有挂起任务 → 等所有 settle
|
|
278
|
+
const timeout = new Promise((resolve) => setTimeout(resolve, Math.max(50, deadline - Date.now())));
|
|
279
|
+
await Promise.race([Promise.allSettled(current), timeout]);
|
|
280
|
+
// 如果所有都清空了 → 完成
|
|
281
|
+
if (this.pendingArchives.size === 0)
|
|
282
|
+
return true;
|
|
283
|
+
// 还有挂起的(可能在等待期间新加入)→ 下一轮继续等
|
|
284
|
+
}
|
|
285
|
+
return this.pendingArchives.size === 0;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
//# sourceMappingURL=messageHistory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messageHistory.js","sourceRoot":"","sources":["../../src/agent/messageHistory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 工具执行器
|
|
3
|
+
*
|
|
4
|
+
* 阶段一:1 个工具(read_file)
|
|
5
|
+
* 阶段二(M-204):扩展为 4 个工具(read_file / write_file / list_dir / search_memories)
|
|
6
|
+
* 详见 ADR-006 · 安全采用两级权限 + 工具白名单 + 路径白名单
|
|
7
|
+
*
|
|
8
|
+
* QC-R2-10 拆分:内置工具实现 + 路径安全已提取到 BuiltinToolHandlers,
|
|
9
|
+
* ToolExecutor 聚焦工具注册 / 分发 / 参数校验。
|
|
10
|
+
*/
|
|
11
|
+
import type { SecurityGuard } from '../security/pathGuard.js';
|
|
12
|
+
import type { IMemoryStorage } from '../memory/storageInterface.js';
|
|
13
|
+
import type { WorkProjectionManager } from '../agent/managers/workProjection.js';
|
|
14
|
+
import { type ToolDefinition } from '../agent/builtinTools.js';
|
|
15
|
+
export { BUILTIN_TOOLS } from '../agent/builtinTools.js';
|
|
16
|
+
export type { ToolDefinition } from '../agent/builtinTools.js';
|
|
17
|
+
type ToolResult = string;
|
|
18
|
+
/**
|
|
19
|
+
* 写入扩展接口
|
|
20
|
+
*
|
|
21
|
+
* 用于在 writeFile 之前注入自定义逻辑(如 diff 展示 + 用户确认)。
|
|
22
|
+
* 当 onBeforeWrite 被提供时,它将替代 SecurityGuard.requestWriteConfirmation 的安全确认流程。
|
|
23
|
+
*/
|
|
24
|
+
export interface WriteExtensions {
|
|
25
|
+
/**
|
|
26
|
+
* 写入前回调
|
|
27
|
+
* @param path 相对路径
|
|
28
|
+
* @param beforeContent 文件旧内容(null 表示新文件)
|
|
29
|
+
* @param afterContent 要写入的新内容
|
|
30
|
+
* @returns true 继续写入,false 拒绝写入
|
|
31
|
+
*/
|
|
32
|
+
onBeforeWrite?: (path: string, beforeContent: string | null, afterContent: string) => Promise<boolean>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 自定义工具的执行上下文
|
|
36
|
+
*
|
|
37
|
+
* S-01: 提供安全校验方法,让自定义工具可以(且应该)通过安全层校验路径。
|
|
38
|
+
* 内置工具(read_file/write_file/list_dir)已内置路径校验,
|
|
39
|
+
* 自定义工具如需访问文件系统,应调用 ctx.guardPath() 确保路径在白名单内。
|
|
40
|
+
*/
|
|
41
|
+
export interface ToolContext {
|
|
42
|
+
/**
|
|
43
|
+
* 校验路径是否在安全白名单内
|
|
44
|
+
*
|
|
45
|
+
* @param path 要校验的路径(相对项目根目录或绝对路径)
|
|
46
|
+
* @throws MemoraError 路径不在白名单内时抛出
|
|
47
|
+
*/
|
|
48
|
+
guardPath: (path: string) => void;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 自定义工具的处理器类型
|
|
52
|
+
*
|
|
53
|
+
* 宿主项目通过 agent.registerTool() 注册领域工具时,
|
|
54
|
+
* 需提供此签名的 handler 函数。
|
|
55
|
+
* handler 接收解析后的参数对象和工具上下文,返回字符串结果。
|
|
56
|
+
*
|
|
57
|
+
* S-01: 自定义工具如需访问文件系统,应调用 ctx.guardPath(path) 校验路径。
|
|
58
|
+
*/
|
|
59
|
+
export type ToolHandler = (args: Record<string, unknown>, ctx: ToolContext) => Promise<string>;
|
|
60
|
+
/**
|
|
61
|
+
* 自定义工具注册条目
|
|
62
|
+
*
|
|
63
|
+
* 将工具定义与处理器绑定在一起,
|
|
64
|
+
* 存入 ToolExecutor 的 customTools Map 中。
|
|
65
|
+
*/
|
|
66
|
+
export interface CustomToolEntry {
|
|
67
|
+
/** 工具定义(名称、描述、参数 schema) */
|
|
68
|
+
definition: ToolDefinition;
|
|
69
|
+
/** 工具执行处理器 */
|
|
70
|
+
handler: ToolHandler;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 工具执行器
|
|
74
|
+
*
|
|
75
|
+
* 职责:工具注册 + 分发 + 参数校验。
|
|
76
|
+
* 内置工具实现委托给 BuiltinToolHandlers(QC-R2-10)。
|
|
77
|
+
*/
|
|
78
|
+
export declare class ToolExecutor {
|
|
79
|
+
/** 自定义工具注册表(宿主项目通过 registerTool 注册领域工具) */
|
|
80
|
+
private readonly customTools;
|
|
81
|
+
/** 内置工具处理器(路径安全 + 内置工具实现,QC-R2-10 提取) */
|
|
82
|
+
private readonly builtinHandlers;
|
|
83
|
+
constructor(projectPath: string, security: SecurityGuard, memoryIndex: IMemoryStorage,
|
|
84
|
+
/** 作品投影管理器(可选,读取文件时自动生成投影) */
|
|
85
|
+
workProjection?: WorkProjectionManager);
|
|
86
|
+
/**
|
|
87
|
+
* 注册自定义工具
|
|
88
|
+
*
|
|
89
|
+
* 宿主项目调用此方法注册领域专属工具(如小说创作的 create_chapter)。
|
|
90
|
+
* 工具名不能与内置工具重复,也不能重复注册。
|
|
91
|
+
* 注册后工具会出现在 `tools.list` 列表中,
|
|
92
|
+
* LLM 可通过 tool_call 调用,execute() 会路由到 handler。
|
|
93
|
+
*
|
|
94
|
+
* @param definition 工具定义(名称、描述、参数 schema)
|
|
95
|
+
* @param handler 工具执行处理器
|
|
96
|
+
* @throws 工具名与内置工具冲突或已注册时抛错
|
|
97
|
+
*/
|
|
98
|
+
registerTool(definition: ToolDefinition, handler: ToolHandler): void;
|
|
99
|
+
/**
|
|
100
|
+
* 获取所有工具定义(IX-02:统一为 getter 风格,与 persona/skill 一致)
|
|
101
|
+
*/
|
|
102
|
+
get list(): ToolDefinition[];
|
|
103
|
+
/**
|
|
104
|
+
* 执行工具调用
|
|
105
|
+
*
|
|
106
|
+
* 新增参数类型校验。
|
|
107
|
+
* LLM 返回的 tool_call 参数可能类型不匹配(如 number 代替 string),
|
|
108
|
+
* 校验器会根据 ToolDefinition.parameters 自动修正常见类型错误,
|
|
109
|
+
* 避免后续 `as string` 强转导致的运行时错误。
|
|
110
|
+
*
|
|
111
|
+
* @param name 工具名称
|
|
112
|
+
* @param argsJson 参数 JSON 字符串
|
|
113
|
+
* @param extensions 写入扩展(可选,用于 diff 确认等)
|
|
114
|
+
* @returns 工具结果的字符串描述
|
|
115
|
+
*/
|
|
116
|
+
execute(name: string, argsJson: string, extensions?: WriteExtensions): Promise<ToolResult>;
|
|
117
|
+
/**
|
|
118
|
+
* 参数类型校验 + 自动修正
|
|
119
|
+
*
|
|
120
|
+
* LLM 返回的 tool_call 参数经常类型不匹配:
|
|
121
|
+
* - number → string(如 maxDepth: 2 而非 "2")
|
|
122
|
+
* - boolean → string(如 recursive: true 而非 "true")
|
|
123
|
+
* - 缺少必填参数
|
|
124
|
+
*
|
|
125
|
+
* 校验策略:
|
|
126
|
+
* 1. 自动修正:number/boolean → string(最常见的 LLM 错误)
|
|
127
|
+
* 2. 缺少必填参数:抛出 toolError
|
|
128
|
+
* 3. 未知参数:忽略(LLM 可能返回额外参数)
|
|
129
|
+
*
|
|
130
|
+
* @param toolName 工具名称(用于错误信息)
|
|
131
|
+
* @param args LLM 返回的原始参数
|
|
132
|
+
* @param definition 工具定义(含参数 schema)
|
|
133
|
+
* @returns 校验/修正后的参数
|
|
134
|
+
*/
|
|
135
|
+
private validateAndCoerceArgs;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=toolExecutor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolExecutor.d.ts","sourceRoot":"","sources":["../../src/agent/toolExecutor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAChF,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE7E,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,KAAK,UAAU,GAAG,MAAM,CAAC;AAEzB;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,CACd,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,YAAY,EAAE,MAAM,KACjB,OAAO,CAAC,OAAO,CAAC,CAAC;CACvB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;;OAKG;IACH,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE/F;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,4BAA4B;IAC5B,UAAU,EAAE,cAAc,CAAC;IAC3B,cAAc;IACd,OAAO,EAAE,WAAW,CAAC;CACtB;AAED;;;;;GAKG;AACH,qBAAa,YAAY;IACvB,2CAA2C;IAC3C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsC;IAClE,yCAAyC;IACzC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAsB;gBAGpD,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,aAAa,EACvB,WAAW,EAAE,cAAc;IAC3B,8BAA8B;IAC9B,cAAc,CAAC,EAAE,qBAAqB;IAYxC;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,UAAU,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI;IAwBpE;;OAEG;IACH,IAAI,IAAI,IAAI,cAAc,EAAE,CAE3B;IAED;;;;;;;;;;;;OAYG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC;IAwGhG;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,qBAAqB;CAyE9B"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { toolError, configError, MemoraError, ToolErrorCode, toError } from '../utils/errors.js';
|
|
2
|
+
import { logger } from '../logging/logger.js';
|
|
3
|
+
import { BUILTIN_TOOLS } from '../agent/builtinTools.js';
|
|
4
|
+
import { BuiltinToolHandlers } from '../agent/builtinToolHandlers.js';
|
|
5
|
+
export { BUILTIN_TOOLS } from '../agent/builtinTools.js';
|
|
6
|
+
/**
|
|
7
|
+
* 工具执行器
|
|
8
|
+
*
|
|
9
|
+
* 职责:工具注册 + 分发 + 参数校验。
|
|
10
|
+
* 内置工具实现委托给 BuiltinToolHandlers(QC-R2-10)。
|
|
11
|
+
*/
|
|
12
|
+
export class ToolExecutor {
|
|
13
|
+
/** 自定义工具注册表(宿主项目通过 registerTool 注册领域工具) */
|
|
14
|
+
customTools = new Map();
|
|
15
|
+
/** 内置工具处理器(路径安全 + 内置工具实现,QC-R2-10 提取) */
|
|
16
|
+
builtinHandlers;
|
|
17
|
+
constructor(projectPath, security, memoryIndex,
|
|
18
|
+
/** 作品投影管理器(可选,读取文件时自动生成投影) */
|
|
19
|
+
workProjection) {
|
|
20
|
+
// QC-R2-10:内置工具实现 + 路径安全委托给 BuiltinToolHandlers
|
|
21
|
+
// 构造参数仅用于初始化 BuiltinToolHandlers,ToolExecutor 自身不再持有这些引用
|
|
22
|
+
this.builtinHandlers = new BuiltinToolHandlers(projectPath, security, memoryIndex, workProjection);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 注册自定义工具
|
|
26
|
+
*
|
|
27
|
+
* 宿主项目调用此方法注册领域专属工具(如小说创作的 create_chapter)。
|
|
28
|
+
* 工具名不能与内置工具重复,也不能重复注册。
|
|
29
|
+
* 注册后工具会出现在 `tools.list` 列表中,
|
|
30
|
+
* LLM 可通过 tool_call 调用,execute() 会路由到 handler。
|
|
31
|
+
*
|
|
32
|
+
* @param definition 工具定义(名称、描述、参数 schema)
|
|
33
|
+
* @param handler 工具执行处理器
|
|
34
|
+
* @throws 工具名与内置工具冲突或已注册时抛错
|
|
35
|
+
*/
|
|
36
|
+
registerTool(definition, handler) {
|
|
37
|
+
if (!definition.name || !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(definition.name)) {
|
|
38
|
+
throw configError(`工具名无效:"${definition.name}"`, '必须以字母/下划线开头,只含字母/数字/下划线', ['请检查工具名称是否符合命名规范']);
|
|
39
|
+
}
|
|
40
|
+
// 不允许覆盖内置工具
|
|
41
|
+
if (BUILTIN_TOOLS.some((t) => t.name === definition.name)) {
|
|
42
|
+
throw configError(`不能覆盖内置工具:${definition.name}`, undefined, [
|
|
43
|
+
'请使用不同的工具名称',
|
|
44
|
+
]);
|
|
45
|
+
}
|
|
46
|
+
// 不允许重复注册
|
|
47
|
+
if (this.customTools.has(definition.name)) {
|
|
48
|
+
throw configError(`工具已注册:${definition.name}`, undefined, [
|
|
49
|
+
'请使用不同的工具名称,或先注销已有工具',
|
|
50
|
+
]);
|
|
51
|
+
}
|
|
52
|
+
this.customTools.set(definition.name, { definition, handler });
|
|
53
|
+
logger.info({ tool: definition.name }, '自定义工具已注册');
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 获取所有工具定义(IX-02:统一为 getter 风格,与 persona/skill 一致)
|
|
57
|
+
*/
|
|
58
|
+
get list() {
|
|
59
|
+
return [...BUILTIN_TOOLS, ...[...this.customTools.values()].map((e) => e.definition)];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 执行工具调用
|
|
63
|
+
*
|
|
64
|
+
* 新增参数类型校验。
|
|
65
|
+
* LLM 返回的 tool_call 参数可能类型不匹配(如 number 代替 string),
|
|
66
|
+
* 校验器会根据 ToolDefinition.parameters 自动修正常见类型错误,
|
|
67
|
+
* 避免后续 `as string` 强转导致的运行时错误。
|
|
68
|
+
*
|
|
69
|
+
* @param name 工具名称
|
|
70
|
+
* @param argsJson 参数 JSON 字符串
|
|
71
|
+
* @param extensions 写入扩展(可选,用于 diff 确认等)
|
|
72
|
+
* @returns 工具结果的字符串描述
|
|
73
|
+
*/
|
|
74
|
+
async execute(name, argsJson, extensions) {
|
|
75
|
+
let args;
|
|
76
|
+
try {
|
|
77
|
+
args = JSON.parse(argsJson);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
const e = toError(err);
|
|
81
|
+
throw toolError('工具参数解析失败', `args JSON 无效:${e.message}`, ['检查 LLM 输出的工具调用格式', '确认 args 是合法 JSON'], e, ToolErrorCode.ARGUMENT_ERROR);
|
|
82
|
+
}
|
|
83
|
+
// 参数类型校验 + 自动修正
|
|
84
|
+
// LLM 经常返回 number 代替 string(如 maxDepth: 2 而非 "2"),
|
|
85
|
+
// 校验器根据 ToolDefinition 自动转换,避免后续 as string 出错
|
|
86
|
+
const definition = this.list.find((t) => t.name === name);
|
|
87
|
+
if (definition) {
|
|
88
|
+
args = this.validateAndCoerceArgs(name, args, definition);
|
|
89
|
+
}
|
|
90
|
+
const safeArgs = Object.fromEntries(Object.entries(args).map(([k, v]) => [
|
|
91
|
+
k,
|
|
92
|
+
typeof v === 'string' && v.length > 200 ? `${v.slice(0, 200)}...` : v,
|
|
93
|
+
]));
|
|
94
|
+
logger.info({ tool: name, args: safeArgs }, '执行工具');
|
|
95
|
+
// 运行时类型安全:从 args 中提取字符串参数,避免不安全的 as string 断言
|
|
96
|
+
const strArg = (key, fallback) => {
|
|
97
|
+
const val = args[key];
|
|
98
|
+
return typeof val === 'string' ? val : (fallback ?? '');
|
|
99
|
+
};
|
|
100
|
+
// QC-R2-10:内置工具调用委托给 BuiltinToolHandlers
|
|
101
|
+
switch (name) {
|
|
102
|
+
case 'read_file':
|
|
103
|
+
return this.builtinHandlers.readFile(strArg('path'));
|
|
104
|
+
case 'write_file':
|
|
105
|
+
return this.builtinHandlers.writeFile(strArg('path'), strArg('content'), extensions, strArg('mode', 'overwrite'), strArg('insert_line') || undefined);
|
|
106
|
+
case 'list_dir':
|
|
107
|
+
return this.builtinHandlers.listDir(strArg('path', '.'), strArg('recursive', 'false'), strArg('maxDepth', '2'));
|
|
108
|
+
case 'search_memories':
|
|
109
|
+
return this.builtinHandlers.searchMemories(strArg('query'), strArg('limit', '10'), strArg('mode', 'match'));
|
|
110
|
+
default: {
|
|
111
|
+
// 自定义工具 fallback:查找 customTools Map
|
|
112
|
+
const custom = this.customTools.get(name);
|
|
113
|
+
if (custom) {
|
|
114
|
+
// S-01: 传入 ToolContext,提供 guardPath 安全校验方法
|
|
115
|
+
// QC-R2-10: 路径安全委托给 BuiltinToolHandlers
|
|
116
|
+
const ctx = {
|
|
117
|
+
guardPath: (path) => {
|
|
118
|
+
const absolutePath = this.builtinHandlers.resolveSafePath(path);
|
|
119
|
+
this.builtinHandlers.guardPathOrThrow(absolutePath, name, 'custom');
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
try {
|
|
123
|
+
return await custom.handler(args, ctx);
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
// 统一包装为 MemoraError,保持错误处理一致性
|
|
127
|
+
if (err instanceof MemoraError)
|
|
128
|
+
throw err;
|
|
129
|
+
const e = toError(err);
|
|
130
|
+
throw toolError('自定义工具执行失败', `${name}: ${e.message}`, ['检查工具参数是否正确', '检查工具 handler 实现是否有 bug'], e, ToolErrorCode.CUSTOM_TOOL_FAILED);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
throw toolError('未知工具', `agent 调用了未注册的工具:${name}`, [
|
|
134
|
+
`已注册工具:${this.list
|
|
135
|
+
.map((t) => t.name)
|
|
136
|
+
.join(', ')}`,
|
|
137
|
+
'检查 personality.md 是否限制了工具集',
|
|
138
|
+
], undefined, ToolErrorCode.UNKNOWN_TOOL);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* 参数类型校验 + 自动修正
|
|
144
|
+
*
|
|
145
|
+
* LLM 返回的 tool_call 参数经常类型不匹配:
|
|
146
|
+
* - number → string(如 maxDepth: 2 而非 "2")
|
|
147
|
+
* - boolean → string(如 recursive: true 而非 "true")
|
|
148
|
+
* - 缺少必填参数
|
|
149
|
+
*
|
|
150
|
+
* 校验策略:
|
|
151
|
+
* 1. 自动修正:number/boolean → string(最常见的 LLM 错误)
|
|
152
|
+
* 2. 缺少必填参数:抛出 toolError
|
|
153
|
+
* 3. 未知参数:忽略(LLM 可能返回额外参数)
|
|
154
|
+
*
|
|
155
|
+
* @param toolName 工具名称(用于错误信息)
|
|
156
|
+
* @param args LLM 返回的原始参数
|
|
157
|
+
* @param definition 工具定义(含参数 schema)
|
|
158
|
+
* @returns 校验/修正后的参数
|
|
159
|
+
*/
|
|
160
|
+
validateAndCoerceArgs(toolName, args, definition) {
|
|
161
|
+
const props = definition.parameters.properties;
|
|
162
|
+
const required = definition.parameters.required;
|
|
163
|
+
const result = { ...args };
|
|
164
|
+
// 检查必填参数
|
|
165
|
+
for (const req of required) {
|
|
166
|
+
if (result[req] === undefined || result[req] === null) {
|
|
167
|
+
throw toolError('工具参数缺失', `${toolName}: 缺少必填参数 "${req}"`, [`参数 "${req}" 类型应为 ${props[req]?.type ?? 'unknown'}`], undefined, ToolErrorCode.ARGUMENT_ERROR);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// 类型修正:根据 schema 中的 type 字段自动转换
|
|
171
|
+
for (const [key, schema] of Object.entries(props)) {
|
|
172
|
+
const value = result[key];
|
|
173
|
+
if (value === undefined || value === null)
|
|
174
|
+
continue; // 可选参数未传,跳过
|
|
175
|
+
const expectedType = schema.type;
|
|
176
|
+
const actualType = typeof value;
|
|
177
|
+
// string 类型修正:number / boolean → string
|
|
178
|
+
if (expectedType === 'string' && actualType !== 'string') {
|
|
179
|
+
result[key] = String(value);
|
|
180
|
+
logger.debug({ tool: toolName, param: key, from: actualType, to: 'string' }, '参数类型自动修正');
|
|
181
|
+
}
|
|
182
|
+
// number 类型修正:string → number
|
|
183
|
+
else if (expectedType === 'number' && actualType === 'string') {
|
|
184
|
+
const num = Number(value);
|
|
185
|
+
if (!Number.isNaN(num)) {
|
|
186
|
+
result[key] = num;
|
|
187
|
+
logger.debug({ tool: toolName, param: key, from: 'string', to: 'number' }, '参数类型自动修正');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// boolean 类型修正:string → boolean
|
|
191
|
+
else if (expectedType === 'boolean' && actualType === 'string') {
|
|
192
|
+
if (value === 'true' || value === '1') {
|
|
193
|
+
result[key] = true;
|
|
194
|
+
}
|
|
195
|
+
else if (value === 'false' || value === '0') {
|
|
196
|
+
result[key] = false;
|
|
197
|
+
}
|
|
198
|
+
logger.debug({ tool: toolName, param: key, from: 'string', to: 'boolean' }, '参数类型自动修正');
|
|
199
|
+
}
|
|
200
|
+
// array 类型修正:单值 → 数组
|
|
201
|
+
else if (expectedType === 'array' && !Array.isArray(value)) {
|
|
202
|
+
result[key] = [value];
|
|
203
|
+
logger.debug({ tool: toolName, param: key, from: actualType, to: 'array' }, '参数类型自动修正');
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=toolExecutor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolExecutor.js","sourceRoot":"","sources":["../../src/agent/toolExecutor.ts"],"names":[],"mappings":"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"}
|