@cicctencent/agent-core 0.1.30 → 0.1.33
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/dist/cjs/agent/engine.d.ts +63 -0
- package/dist/cjs/agent/engine.d.ts.map +1 -1
- package/dist/cjs/agent/engine.js +253 -22
- package/dist/cjs/agent/engine.js.map +1 -1
- package/dist/cjs/agent/llm-caller.d.ts +22 -1
- package/dist/cjs/agent/llm-caller.d.ts.map +1 -1
- package/dist/cjs/agent/llm-caller.js +163 -7
- package/dist/cjs/agent/llm-caller.js.map +1 -1
- package/dist/cjs/agent/rate-limit-manager.d.ts +137 -0
- package/dist/cjs/agent/rate-limit-manager.d.ts.map +1 -0
- package/dist/cjs/agent/rate-limit-manager.js +488 -0
- package/dist/cjs/agent/rate-limit-manager.js.map +1 -0
- package/dist/cjs/agent/tool-executor.d.ts +11 -0
- package/dist/cjs/agent/tool-executor.d.ts.map +1 -1
- package/dist/cjs/agent/tool-executor.js +95 -4
- package/dist/cjs/agent/tool-executor.js.map +1 -1
- package/dist/cjs/agent/types.d.ts +73 -2
- package/dist/cjs/agent/types.d.ts.map +1 -1
- package/dist/cjs/agent/types.js.map +1 -1
- package/dist/cjs/agent/workflow.d.ts.map +1 -1
- package/dist/cjs/agent/workflow.js +12 -7
- package/dist/cjs/agent/workflow.js.map +1 -1
- package/dist/cjs/index.d.ts +3 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +19 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/runtime/run-registry.d.ts +2 -0
- package/dist/cjs/runtime/run-registry.d.ts.map +1 -1
- package/dist/cjs/runtime/run-registry.js +24 -1
- package/dist/cjs/runtime/run-registry.js.map +1 -1
- package/dist/cjs/utils/dsml-parser.d.ts +1 -1
- package/dist/cjs/utils/dsml-parser.d.ts.map +1 -1
- package/dist/cjs/utils/dsml-parser.js +16 -3
- package/dist/cjs/utils/dsml-parser.js.map +1 -1
- package/dist/cjs/utils/safe-truncate.d.ts +34 -0
- package/dist/cjs/utils/safe-truncate.d.ts.map +1 -0
- package/dist/cjs/utils/safe-truncate.js +72 -0
- package/dist/cjs/utils/safe-truncate.js.map +1 -0
- package/dist/esm/agent/engine.d.ts +63 -0
- package/dist/esm/agent/engine.d.ts.map +1 -1
- package/dist/esm/agent/engine.js +253 -22
- package/dist/esm/agent/engine.js.map +1 -1
- package/dist/esm/agent/llm-caller.d.ts +22 -1
- package/dist/esm/agent/llm-caller.d.ts.map +1 -1
- package/dist/esm/agent/llm-caller.js +163 -7
- package/dist/esm/agent/llm-caller.js.map +1 -1
- package/dist/esm/agent/rate-limit-manager.d.ts +137 -0
- package/dist/esm/agent/rate-limit-manager.d.ts.map +1 -0
- package/dist/esm/agent/rate-limit-manager.js +486 -0
- package/dist/esm/agent/rate-limit-manager.js.map +1 -0
- package/dist/esm/agent/tool-executor.d.ts +11 -0
- package/dist/esm/agent/tool-executor.d.ts.map +1 -1
- package/dist/esm/agent/tool-executor.js +95 -4
- package/dist/esm/agent/tool-executor.js.map +1 -1
- package/dist/esm/agent/types.d.ts +73 -2
- package/dist/esm/agent/types.d.ts.map +1 -1
- package/dist/esm/agent/types.js.map +1 -1
- package/dist/esm/agent/workflow.d.ts.map +1 -1
- package/dist/esm/agent/workflow.js +12 -7
- package/dist/esm/agent/workflow.js.map +1 -1
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/runtime/run-registry.d.ts +2 -0
- package/dist/esm/runtime/run-registry.d.ts.map +1 -1
- package/dist/esm/runtime/run-registry.js +24 -1
- package/dist/esm/runtime/run-registry.js.map +1 -1
- package/dist/esm/utils/dsml-parser.d.ts +1 -1
- package/dist/esm/utils/dsml-parser.d.ts.map +1 -1
- package/dist/esm/utils/dsml-parser.js +16 -3
- package/dist/esm/utils/dsml-parser.js.map +1 -1
- package/dist/esm/utils/safe-truncate.d.ts +34 -0
- package/dist/esm/utils/safe-truncate.d.ts.map +1 -0
- package/dist/esm/utils/safe-truncate.js +65 -0
- package/dist/esm/utils/safe-truncate.js.map +1 -0
- package/package.json +1 -1
|
@@ -10,6 +10,10 @@ export declare class AgentEngine {
|
|
|
10
10
|
private abortMap;
|
|
11
11
|
/** sessionId → steering messages(实时转向队列) */
|
|
12
12
|
private steeringMap;
|
|
13
|
+
/** parentSessionId → Set<childSessionId>(父子会话关系跟踪,用于级联 abort) */
|
|
14
|
+
private childSessionMap;
|
|
15
|
+
/** childSessionId → parentSessionId(反向索引,用于快速查找父会话) */
|
|
16
|
+
private parentSessionMap;
|
|
13
17
|
/** 子模块:历史管理器 */
|
|
14
18
|
private historyManager;
|
|
15
19
|
/** 子模块:LLM 调用器 */
|
|
@@ -26,6 +30,8 @@ export declare class AgentEngine {
|
|
|
26
30
|
private outputTools;
|
|
27
31
|
/** Guard 策略配置(阈值可注入,不硬编码业务逻辑) */
|
|
28
32
|
private guardConfig;
|
|
33
|
+
/** 错误恢复策略配置 */
|
|
34
|
+
private errorRecovery;
|
|
29
35
|
constructor(config: AgentConfig);
|
|
30
36
|
/** 获取当前 Agent 的 ToolRegistry(供 read_tool_doc 等内置工具使用) */
|
|
31
37
|
getToolRegistry(): ToolRegistry;
|
|
@@ -65,6 +71,29 @@ export declare class AgentEngine {
|
|
|
65
71
|
forkHistory(sourceSessionId: string, targetSessionId: string, fromIndex?: number): number;
|
|
66
72
|
/** 获取会话历史的消息数量 */
|
|
67
73
|
getHistoryLength(sessionId: string): number;
|
|
74
|
+
/**
|
|
75
|
+
* 注册父子会话关系。
|
|
76
|
+
*
|
|
77
|
+
* 典型场景:主 Agent 通过 delegate_task 工具派生子任务时,
|
|
78
|
+
* 上层调用此方法将子会话与父会话关联。当父会话因异常终止时,
|
|
79
|
+
* 如果配置了 `cascadeAbortChildren`,所有子会话也会被自动 abort。
|
|
80
|
+
*
|
|
81
|
+
* @param parentSessionId 父会话 ID
|
|
82
|
+
* @param childSessionId 子会话 ID
|
|
83
|
+
*/
|
|
84
|
+
linkChildSession(parentSessionId: string, childSessionId: string): void;
|
|
85
|
+
/**
|
|
86
|
+
* 解除父子会话关系(子会话完成后调用)。
|
|
87
|
+
*/
|
|
88
|
+
unlinkChildSession(childSessionId: string): void;
|
|
89
|
+
/**
|
|
90
|
+
* 获取指定父会话的所有子会话 ID。
|
|
91
|
+
*/
|
|
92
|
+
getChildSessions(parentSessionId: string): string[];
|
|
93
|
+
/**
|
|
94
|
+
* 获取指定子会话的父会话 ID(如有)。
|
|
95
|
+
*/
|
|
96
|
+
getParentSession(childSessionId: string): string | undefined;
|
|
68
97
|
/**
|
|
69
98
|
* 执行 Agent 任务(流式推送事件)
|
|
70
99
|
* 上层通过 for-await-of 消费事件流
|
|
@@ -105,6 +134,12 @@ export declare class AgentEngine {
|
|
|
105
134
|
private refreshSummaryCache;
|
|
106
135
|
/** 获取工具定义列表(含预过滤 + 渐进式发现) */
|
|
107
136
|
private resolveToolDefs;
|
|
137
|
+
/**
|
|
138
|
+
* 将工具定义转为摘要形式(截断 description + 清空 parameters)。
|
|
139
|
+
* @param def 原始工具定义
|
|
140
|
+
* @param scope 摘要范围:'mcp'=仅MCP工具摘要, 'all'=所有传入工具摘要, null=保持原样
|
|
141
|
+
*/
|
|
142
|
+
private summarizeToolDef;
|
|
108
143
|
/** 构建 ToolContext */
|
|
109
144
|
private buildToolContext;
|
|
110
145
|
/** 汇总准备阶段,生成 LoopState */
|
|
@@ -161,10 +196,38 @@ export declare class AgentEngine {
|
|
|
161
196
|
private emitDone;
|
|
162
197
|
/** 中断指定会话的 Agent 执行 */
|
|
163
198
|
abort(sessionId: string): void;
|
|
199
|
+
/**
|
|
200
|
+
* 中断指定会话及其所有子会话的 Agent 执行(级联 abort)。
|
|
201
|
+
*
|
|
202
|
+
* 递归遍历子会话树,从叶子节点到根节点依次 abort。
|
|
203
|
+
* 用于确保父会话异常终止时,所有 delegate_task 派生的子任务也被终止。
|
|
204
|
+
*/
|
|
205
|
+
abortCascade(sessionId: string): void;
|
|
164
206
|
/** 查询指定会话的 Agent 状态 */
|
|
165
207
|
getStatus(sessionId: string): AgentStatus;
|
|
166
208
|
/** 销毁引擎,释放所有会话资源 */
|
|
167
209
|
destroy(): void;
|
|
210
|
+
/**
|
|
211
|
+
* 统一的致命错误处理入口。
|
|
212
|
+
*
|
|
213
|
+
* 由引擎内部(agentLoop、catch 块)在遇到不可恢复错误时调用。
|
|
214
|
+
* 按以下顺序执行:
|
|
215
|
+
* 1. 调用 config.errorRecovery.onFatalError 回调(允许上层记录/通知)
|
|
216
|
+
* 2. 如果 config.errorRecovery.autoAbortOnFatal,abort 当前会话
|
|
217
|
+
* 3. 如果 config.errorRecovery.cascadeAbortChildren,级联 abort 所有子会话
|
|
218
|
+
*
|
|
219
|
+
* @param error 致命错误信息(含 sessionId)
|
|
220
|
+
*/
|
|
221
|
+
private handleFatalError;
|
|
222
|
+
/**
|
|
223
|
+
* 清理指定会话的父子关系记录。
|
|
224
|
+
*
|
|
225
|
+
* 在会话自然完成或 abort 后调用,防止内存泄漏。
|
|
226
|
+
* 处理两个方向:
|
|
227
|
+
* - 如果是父会话:移除所有子会话引用(但子会话若仍在运行则保留其关系)
|
|
228
|
+
* - 如果是子会话:从父会话的子集中移除自身
|
|
229
|
+
*/
|
|
230
|
+
private cleanupSessionRelations;
|
|
168
231
|
createEvent(sessionId: string, event: Record<string, unknown>): AgentEvent;
|
|
169
232
|
private createNoopShell;
|
|
170
233
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/agent/engine.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAoE,MAAM,aAAa,CAAC;AAItI,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/agent/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/cjs/agent/engine.js
CHANGED
|
@@ -11,8 +11,31 @@ const history_manager_ts_1 = require("./history-manager.js");
|
|
|
11
11
|
const llm_caller_ts_1 = require("./llm-caller.js");
|
|
12
12
|
const tool_executor_ts_1 = require("./tool-executor.js");
|
|
13
13
|
const logger_ts_1 = require("../observability/logger.js");
|
|
14
|
+
const rate_limit_manager_ts_1 = require("./rate-limit-manager.js");
|
|
14
15
|
/** 默认系统提示词 */
|
|
15
16
|
const DEFAULT_BASE_PROMPT = `You are a helpful AI assistant with access to tools. Use tools when needed to accomplish tasks. Always explain your actions clearly.`;
|
|
17
|
+
/**
|
|
18
|
+
* 核心工具集(summary-all 模式下保持全量 schema 的工具)。
|
|
19
|
+
*
|
|
20
|
+
* 这些工具是 Agent 执行绝大多数任务的基础(文件读写、代码搜索、命令执行、
|
|
21
|
+
* 工具发现、委托派发),必须让 LLM 看到完整参数 schema 以保证调用可靠性。
|
|
22
|
+
* 非核心工具(通讯、日历、自动化、文档生成等)仅以摘要形式呈现,
|
|
23
|
+
* LLM 需通过 read_tool_doc 获取完整 schema 后再调用。
|
|
24
|
+
*/
|
|
25
|
+
const CORE_TOOL_NAMES = new Set([
|
|
26
|
+
'read_file',
|
|
27
|
+
'write_file',
|
|
28
|
+
'edit_file',
|
|
29
|
+
'append_file',
|
|
30
|
+
'search_code',
|
|
31
|
+
'execute_command',
|
|
32
|
+
'run_script',
|
|
33
|
+
'read_terminal',
|
|
34
|
+
'read_tool_doc',
|
|
35
|
+
'read_tool_result',
|
|
36
|
+
'read_offload',
|
|
37
|
+
'delegate_task',
|
|
38
|
+
]);
|
|
16
39
|
/** 进度叙述规则(追加到 system prompt,引导 LLM 在工具调用间输出可见文本)— 可通过 AgentConfig.progressNarrationRules 覆盖 */
|
|
17
40
|
const DEFAULT_PROGRESS_NARRATION_RULES = `
|
|
18
41
|
|
|
@@ -85,6 +108,10 @@ class AgentEngine {
|
|
|
85
108
|
abortMap = new Map();
|
|
86
109
|
/** sessionId → steering messages(实时转向队列) */
|
|
87
110
|
steeringMap = new Map();
|
|
111
|
+
/** parentSessionId → Set<childSessionId>(父子会话关系跟踪,用于级联 abort) */
|
|
112
|
+
childSessionMap = new Map();
|
|
113
|
+
/** childSessionId → parentSessionId(反向索引,用于快速查找父会话) */
|
|
114
|
+
parentSessionMap = new Map();
|
|
88
115
|
/** 子模块:历史管理器 */
|
|
89
116
|
historyManager;
|
|
90
117
|
/** 子模块:LLM 调用器 */
|
|
@@ -101,6 +128,8 @@ class AgentEngine {
|
|
|
101
128
|
outputTools;
|
|
102
129
|
/** Guard 策略配置(阈值可注入,不硬编码业务逻辑) */
|
|
103
130
|
guardConfig;
|
|
131
|
+
/** 错误恢复策略配置 */
|
|
132
|
+
errorRecovery;
|
|
104
133
|
constructor(config) {
|
|
105
134
|
this.config = {
|
|
106
135
|
...config,
|
|
@@ -159,6 +188,13 @@ class AgentEngine {
|
|
|
159
188
|
delegateTargets: gc.delegateTargets ?? {},
|
|
160
189
|
iterationGuardPrompt: gc.iterationGuardPrompt ?? '',
|
|
161
190
|
};
|
|
191
|
+
// 初始化错误恢复策略
|
|
192
|
+
const er = config.errorRecovery ?? {};
|
|
193
|
+
this.errorRecovery = {
|
|
194
|
+
autoAbortOnFatal: er.autoAbortOnFatal ?? true,
|
|
195
|
+
cascadeAbortChildren: er.cascadeAbortChildren ?? false,
|
|
196
|
+
onFatalError: er.onFatalError ?? undefined,
|
|
197
|
+
};
|
|
162
198
|
}
|
|
163
199
|
/** 获取当前 Agent 的 ToolRegistry(供 read_tool_doc 等内置工具使用) */
|
|
164
200
|
getToolRegistry() {
|
|
@@ -216,6 +252,51 @@ class AgentEngine {
|
|
|
216
252
|
getHistoryLength(sessionId) {
|
|
217
253
|
return this.historyManager.getHistoryLength(sessionId);
|
|
218
254
|
}
|
|
255
|
+
// ---- 父子会话关系管理 ----
|
|
256
|
+
/**
|
|
257
|
+
* 注册父子会话关系。
|
|
258
|
+
*
|
|
259
|
+
* 典型场景:主 Agent 通过 delegate_task 工具派生子任务时,
|
|
260
|
+
* 上层调用此方法将子会话与父会话关联。当父会话因异常终止时,
|
|
261
|
+
* 如果配置了 `cascadeAbortChildren`,所有子会话也会被自动 abort。
|
|
262
|
+
*
|
|
263
|
+
* @param parentSessionId 父会话 ID
|
|
264
|
+
* @param childSessionId 子会话 ID
|
|
265
|
+
*/
|
|
266
|
+
linkChildSession(parentSessionId, childSessionId) {
|
|
267
|
+
if (!this.childSessionMap.has(parentSessionId)) {
|
|
268
|
+
this.childSessionMap.set(parentSessionId, new Set());
|
|
269
|
+
}
|
|
270
|
+
this.childSessionMap.get(parentSessionId).add(childSessionId);
|
|
271
|
+
this.parentSessionMap.set(childSessionId, parentSessionId);
|
|
272
|
+
// 通知 RateLimitManager 建立父子映射(用于 429 终止主会话时定位父会话)
|
|
273
|
+
rate_limit_manager_ts_1.rateLimitManager.registerSubSession(childSessionId, parentSessionId);
|
|
274
|
+
(0, logger_ts_1.logEvent)({ event: 'engine.child_linked', sessionId: parentSessionId, data: { childSessionId } });
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* 解除父子会话关系(子会话完成后调用)。
|
|
278
|
+
*/
|
|
279
|
+
unlinkChildSession(childSessionId) {
|
|
280
|
+
const parentId = this.parentSessionMap.get(childSessionId);
|
|
281
|
+
if (parentId) {
|
|
282
|
+
this.childSessionMap.get(parentId)?.delete(childSessionId);
|
|
283
|
+
this.parentSessionMap.delete(childSessionId);
|
|
284
|
+
}
|
|
285
|
+
// 通知 RateLimitManager 注销子会话,释放并发槽位
|
|
286
|
+
rate_limit_manager_ts_1.rateLimitManager.unregisterSubSession(childSessionId);
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* 获取指定父会话的所有子会话 ID。
|
|
290
|
+
*/
|
|
291
|
+
getChildSessions(parentSessionId) {
|
|
292
|
+
return Array.from(this.childSessionMap.get(parentSessionId) ?? []);
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* 获取指定子会话的父会话 ID(如有)。
|
|
296
|
+
*/
|
|
297
|
+
getParentSession(childSessionId) {
|
|
298
|
+
return this.parentSessionMap.get(childSessionId);
|
|
299
|
+
}
|
|
219
300
|
/**
|
|
220
301
|
* 执行 Agent 任务(流式推送事件)
|
|
221
302
|
* 上层通过 for-await-of 消费事件流
|
|
@@ -225,6 +306,8 @@ class AgentEngine {
|
|
|
225
306
|
// ① Abort 控制
|
|
226
307
|
const internalAbort = new AbortController();
|
|
227
308
|
this.abortMap.set(sessionId, internalAbort);
|
|
309
|
+
// 注册到 RateLimitManager,使其能在多轮冷却失败时终止主会话
|
|
310
|
+
rate_limit_manager_ts_1.rateLimitManager.registerMainSession(sessionId, internalAbort);
|
|
228
311
|
const onExternalAbort = () => internalAbort.abort();
|
|
229
312
|
if (abortSignal) {
|
|
230
313
|
if (abortSignal.aborted)
|
|
@@ -246,6 +329,15 @@ class AgentEngine {
|
|
|
246
329
|
error: errorMsg,
|
|
247
330
|
recoverable: false,
|
|
248
331
|
});
|
|
332
|
+
// 致命错误 → 自动 abort + 级联清理
|
|
333
|
+
await this.handleFatalError({
|
|
334
|
+
sessionId,
|
|
335
|
+
errorType: 'unexpected_exception',
|
|
336
|
+
error: errorMsg,
|
|
337
|
+
timestamp: Date.now(),
|
|
338
|
+
iteration: 0,
|
|
339
|
+
rawError: err,
|
|
340
|
+
});
|
|
249
341
|
this.statusMap.set(sessionId, 'idle');
|
|
250
342
|
}
|
|
251
343
|
finally {
|
|
@@ -253,6 +345,8 @@ class AgentEngine {
|
|
|
253
345
|
abortSignal.removeEventListener('abort', onExternalAbort);
|
|
254
346
|
this.abortMap.delete(sessionId);
|
|
255
347
|
this.steeringMap.delete(sessionId);
|
|
348
|
+
// 注销主会话,清理限流状态和子会话映射
|
|
349
|
+
rate_limit_manager_ts_1.rateLimitManager.unregisterMainSession(sessionId);
|
|
256
350
|
}
|
|
257
351
|
}
|
|
258
352
|
// ---- 准备阶段 ----
|
|
@@ -539,32 +633,51 @@ ${textHistory.join('\n')}`;
|
|
|
539
633
|
const denied = new Set(this.config.deniedTools);
|
|
540
634
|
defs = defs.filter(d => !denied.has(d.function.name));
|
|
541
635
|
}
|
|
542
|
-
|
|
636
|
+
const discovery = this.config.toolDiscovery;
|
|
637
|
+
// summary 模式:仅 MCP 工具摘要
|
|
638
|
+
if (discovery === 'summary') {
|
|
639
|
+
defs = defs.map(d => this.summarizeToolDef(d, 'mcp'));
|
|
640
|
+
}
|
|
641
|
+
// summary-all 模式:所有非核心工具摘要(MCP + 非核心内置工具)
|
|
642
|
+
if (discovery === 'summary-all') {
|
|
643
|
+
const coreOverride = this.config.coreToolNames
|
|
644
|
+
? new Set(this.config.coreToolNames)
|
|
645
|
+
: CORE_TOOL_NAMES;
|
|
543
646
|
defs = defs.map(d => {
|
|
544
|
-
const
|
|
545
|
-
|
|
546
|
-
const maxDesc = this.config.toolSummaryMaxDesc ?? 100;
|
|
547
|
-
const desc = d.function.description.length > maxDesc
|
|
548
|
-
? d.function.description.slice(0, maxDesc) + '...'
|
|
549
|
-
: d.function.description;
|
|
550
|
-
return {
|
|
551
|
-
type: 'function',
|
|
552
|
-
function: {
|
|
553
|
-
name: d.function.name,
|
|
554
|
-
description: desc + ` (use read_tool_doc to get full schema before calling; use read_tool_doc(tool_name="list") to see all available tools)`,
|
|
555
|
-
parameters: {
|
|
556
|
-
type: 'object',
|
|
557
|
-
properties: {},
|
|
558
|
-
required: [],
|
|
559
|
-
},
|
|
560
|
-
},
|
|
561
|
-
};
|
|
562
|
-
}
|
|
563
|
-
return d;
|
|
647
|
+
const isCore = coreOverride.has(d.function.name);
|
|
648
|
+
return this.summarizeToolDef(d, isCore ? null : 'all');
|
|
564
649
|
});
|
|
565
650
|
}
|
|
566
651
|
return defs;
|
|
567
652
|
}
|
|
653
|
+
/**
|
|
654
|
+
* 将工具定义转为摘要形式(截断 description + 清空 parameters)。
|
|
655
|
+
* @param def 原始工具定义
|
|
656
|
+
* @param scope 摘要范围:'mcp'=仅MCP工具摘要, 'all'=所有传入工具摘要, null=保持原样
|
|
657
|
+
*/
|
|
658
|
+
summarizeToolDef(def, scope) {
|
|
659
|
+
if (scope === null)
|
|
660
|
+
return def;
|
|
661
|
+
const tool = this.config.toolRegistry.get(def.function.name);
|
|
662
|
+
if (scope === 'mcp' && tool?.category !== 'mcp')
|
|
663
|
+
return def;
|
|
664
|
+
const maxDesc = this.config.toolSummaryMaxDesc ?? 100;
|
|
665
|
+
const desc = def.function.description.length > maxDesc
|
|
666
|
+
? def.function.description.slice(0, maxDesc) + '...'
|
|
667
|
+
: def.function.description;
|
|
668
|
+
return {
|
|
669
|
+
type: 'function',
|
|
670
|
+
function: {
|
|
671
|
+
name: def.function.name,
|
|
672
|
+
description: desc + ` (use read_tool_doc to get full schema before calling; use read_tool_doc(tool_name="list") to see all available tools)`,
|
|
673
|
+
parameters: {
|
|
674
|
+
type: 'object',
|
|
675
|
+
properties: {},
|
|
676
|
+
required: [],
|
|
677
|
+
},
|
|
678
|
+
},
|
|
679
|
+
};
|
|
680
|
+
}
|
|
568
681
|
// ---- 准备阶段(续) ----
|
|
569
682
|
/** 构建 ToolContext */
|
|
570
683
|
buildToolContext(options, internalAbort) {
|
|
@@ -623,12 +736,21 @@ ${textHistory.join('\n')}`;
|
|
|
623
736
|
const budgetCheck = this.config.usageTracker.checkBudget(state.sessionId, this.config.tokenBudget);
|
|
624
737
|
if (budgetCheck.exceeded) {
|
|
625
738
|
if (this.config.tokenBudget.onExceed === 'abort') {
|
|
739
|
+
const budgetErrMsg = `Token budget exceeded (${budgetCheck.currentTokens}/${budgetCheck.maxTokens} tokens). Task aborted to prevent cost overrun.`;
|
|
626
740
|
(0, logger_ts_1.logEvent)({ event: 'engine.token_budget_exceeded', sessionId: state.sessionId, level: 'warn', data: { current: budgetCheck.currentTokens, max: budgetCheck.maxTokens, action: 'abort' } });
|
|
627
741
|
yield this.createEvent(state.sessionId, {
|
|
628
742
|
type: 'error',
|
|
629
|
-
error:
|
|
743
|
+
error: budgetErrMsg,
|
|
630
744
|
recoverable: false,
|
|
631
745
|
});
|
|
746
|
+
// 致命错误 → 自动 abort + 级联清理
|
|
747
|
+
await this.handleFatalError({
|
|
748
|
+
sessionId: state.sessionId,
|
|
749
|
+
errorType: 'token_budget_exceeded',
|
|
750
|
+
error: budgetErrMsg,
|
|
751
|
+
timestamp: Date.now(),
|
|
752
|
+
iteration: state.iteration,
|
|
753
|
+
});
|
|
632
754
|
yield this.emitDone(state);
|
|
633
755
|
return;
|
|
634
756
|
}
|
|
@@ -674,8 +796,17 @@ ${textHistory.join('\n')}`;
|
|
|
674
796
|
// 所有 LLM provider 均已失败(callWithRetry 内部已重试+降级),
|
|
675
797
|
// 不再发 done 事件(callWithRetry 已发出带详细错误信息的 error 事件),
|
|
676
798
|
// 仅完成清理,避免 done 事件覆盖前端已展示的错误消息
|
|
799
|
+
const errorMsg = 'All LLM providers exhausted (all calls failed including retries and fallback)';
|
|
677
800
|
(0, logger_ts_1.logEvent)({ event: 'engine.llm_exhausted', sessionId: state.sessionId, level: 'warn', data: { iteration: state.iteration } });
|
|
678
801
|
this.statusMap.set(state.sessionId, 'idle');
|
|
802
|
+
// 致命错误 → 自动 abort + 级联清理(级联清理子 Agent 运行中的子任务)
|
|
803
|
+
await this.handleFatalError({
|
|
804
|
+
sessionId: state.sessionId,
|
|
805
|
+
errorType: 'llm_exhausted',
|
|
806
|
+
error: errorMsg,
|
|
807
|
+
timestamp: Date.now(),
|
|
808
|
+
iteration: state.iteration,
|
|
809
|
+
});
|
|
679
810
|
// 记录 Token 用量到 UsageTracker
|
|
680
811
|
if (this.config.usageTracker && state.totalUsage) {
|
|
681
812
|
const modelInfo = this.config.llmProvider.getModel();
|
|
@@ -748,7 +879,16 @@ ${textHistory.join('\n')}`;
|
|
|
748
879
|
if (allFailed) {
|
|
749
880
|
state.consecutiveAllFailIterations++;
|
|
750
881
|
if (state.consecutiveAllFailIterations >= this.guardConfig.consecutiveAllFailThreshold) {
|
|
882
|
+
const failMsg = `All tool calls failed for ${state.consecutiveAllFailIterations} consecutive iterations`;
|
|
751
883
|
(0, logger_ts_1.logEvent)({ event: 'engine.global_fail_breaker', sessionId: state.sessionId, level: 'warn', data: { consecutiveFails: state.consecutiveAllFailIterations, iteration: state.iteration } });
|
|
884
|
+
// 致命错误 → 自动 abort + 级联清理
|
|
885
|
+
await this.handleFatalError({
|
|
886
|
+
sessionId: state.sessionId,
|
|
887
|
+
errorType: 'all_tools_failed',
|
|
888
|
+
error: failMsg,
|
|
889
|
+
timestamp: Date.now(),
|
|
890
|
+
iteration: state.iteration,
|
|
891
|
+
});
|
|
752
892
|
yield this.emitDone(state);
|
|
753
893
|
return;
|
|
754
894
|
}
|
|
@@ -1059,6 +1199,8 @@ ${textHistory.join('\n')}`;
|
|
|
1059
1199
|
// ---- 辅助 ----
|
|
1060
1200
|
emitDone(state) {
|
|
1061
1201
|
this.statusMap.set(state.sessionId, 'idle');
|
|
1202
|
+
// 会话正常结束时清理父子关系(不级联 abort,子会话可自行运行完成)
|
|
1203
|
+
this.cleanupSessionRelations(state.sessionId);
|
|
1062
1204
|
// 记录 Token 用量到 UsageTracker
|
|
1063
1205
|
if (this.config.usageTracker && state.totalUsage) {
|
|
1064
1206
|
const modelInfo = this.config.llmProvider.getModel();
|
|
@@ -1089,7 +1231,24 @@ ${textHistory.join('\n')}`;
|
|
|
1089
1231
|
if (controller) {
|
|
1090
1232
|
controller.abort();
|
|
1091
1233
|
this.statusMap.set(sessionId, 'aborting');
|
|
1234
|
+
(0, logger_ts_1.logEvent)({ event: 'engine.abort', sessionId, data: { reason: 'abort() called' } });
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
/**
|
|
1238
|
+
* 中断指定会话及其所有子会话的 Agent 执行(级联 abort)。
|
|
1239
|
+
*
|
|
1240
|
+
* 递归遍历子会话树,从叶子节点到根节点依次 abort。
|
|
1241
|
+
* 用于确保父会话异常终止时,所有 delegate_task 派生的子任务也被终止。
|
|
1242
|
+
*/
|
|
1243
|
+
abortCascade(sessionId) {
|
|
1244
|
+
this.abort(sessionId);
|
|
1245
|
+
// 遍历直接子会话,递归 abort
|
|
1246
|
+
const children = this.getChildSessions(sessionId);
|
|
1247
|
+
for (const childId of children) {
|
|
1248
|
+
this.abortCascade(childId);
|
|
1092
1249
|
}
|
|
1250
|
+
// 清理父子关系
|
|
1251
|
+
this.cleanupSessionRelations(sessionId);
|
|
1093
1252
|
}
|
|
1094
1253
|
/** 查询指定会话的 Agent 状态 */
|
|
1095
1254
|
getStatus(sessionId) {
|
|
@@ -1103,9 +1262,81 @@ ${textHistory.join('\n')}`;
|
|
|
1103
1262
|
this.abortMap.clear();
|
|
1104
1263
|
this.statusMap.clear();
|
|
1105
1264
|
this.steeringMap.clear();
|
|
1265
|
+
this.childSessionMap.clear();
|
|
1266
|
+
this.parentSessionMap.clear();
|
|
1106
1267
|
this.summaryCache.clear();
|
|
1107
1268
|
this.historyManager.clearAll();
|
|
1108
1269
|
}
|
|
1270
|
+
// ---- 致命错误处理 ----
|
|
1271
|
+
/**
|
|
1272
|
+
* 统一的致命错误处理入口。
|
|
1273
|
+
*
|
|
1274
|
+
* 由引擎内部(agentLoop、catch 块)在遇到不可恢复错误时调用。
|
|
1275
|
+
* 按以下顺序执行:
|
|
1276
|
+
* 1. 调用 config.errorRecovery.onFatalError 回调(允许上层记录/通知)
|
|
1277
|
+
* 2. 如果 config.errorRecovery.autoAbortOnFatal,abort 当前会话
|
|
1278
|
+
* 3. 如果 config.errorRecovery.cascadeAbortChildren,级联 abort 所有子会话
|
|
1279
|
+
*
|
|
1280
|
+
* @param error 致命错误信息(含 sessionId)
|
|
1281
|
+
*/
|
|
1282
|
+
async handleFatalError(error) {
|
|
1283
|
+
(0, logger_ts_1.logEvent)({
|
|
1284
|
+
event: 'engine.fatal_error',
|
|
1285
|
+
sessionId: error.sessionId,
|
|
1286
|
+
level: 'error',
|
|
1287
|
+
data: {
|
|
1288
|
+
errorType: error.errorType,
|
|
1289
|
+
error: error.error,
|
|
1290
|
+
iteration: error.iteration,
|
|
1291
|
+
autoAbort: this.errorRecovery.autoAbortOnFatal,
|
|
1292
|
+
cascadeAbort: this.errorRecovery.cascadeAbortChildren,
|
|
1293
|
+
},
|
|
1294
|
+
});
|
|
1295
|
+
// ① 外部回调通知(不阻塞后续清理流程)
|
|
1296
|
+
if (this.errorRecovery.onFatalError) {
|
|
1297
|
+
try {
|
|
1298
|
+
await this.errorRecovery.onFatalError(error);
|
|
1299
|
+
}
|
|
1300
|
+
catch (e) {
|
|
1301
|
+
// 回调异常不影响后续清理流程
|
|
1302
|
+
(0, logger_ts_1.logEvent)({
|
|
1303
|
+
event: 'engine.fatal_error_callback_failed',
|
|
1304
|
+
sessionId: error.sessionId,
|
|
1305
|
+
level: 'warn',
|
|
1306
|
+
data: { error: e?.message || String(e) },
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
// ② 自动 abort 当前会话
|
|
1311
|
+
if (this.errorRecovery.autoAbortOnFatal) {
|
|
1312
|
+
if (this.errorRecovery.cascadeAbortChildren) {
|
|
1313
|
+
// 级联 abort:终止当前会话及其所有子孙会话
|
|
1314
|
+
this.abortCascade(error.sessionId);
|
|
1315
|
+
}
|
|
1316
|
+
else {
|
|
1317
|
+
// 仅 abort 当前会话
|
|
1318
|
+
this.abort(error.sessionId);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
/**
|
|
1323
|
+
* 清理指定会话的父子关系记录。
|
|
1324
|
+
*
|
|
1325
|
+
* 在会话自然完成或 abort 后调用,防止内存泄漏。
|
|
1326
|
+
* 处理两个方向:
|
|
1327
|
+
* - 如果是父会话:移除所有子会话引用(但子会话若仍在运行则保留其关系)
|
|
1328
|
+
* - 如果是子会话:从父会话的子集中移除自身
|
|
1329
|
+
*/
|
|
1330
|
+
cleanupSessionRelations(sessionId) {
|
|
1331
|
+
// 从父会话的子集中移除自身
|
|
1332
|
+
const parentId = this.parentSessionMap.get(sessionId);
|
|
1333
|
+
if (parentId) {
|
|
1334
|
+
this.childSessionMap.get(parentId)?.delete(sessionId);
|
|
1335
|
+
this.parentSessionMap.delete(sessionId);
|
|
1336
|
+
}
|
|
1337
|
+
// 删除自身作为父会话的所有子关系记录(但保留子会话本身仍在运行)
|
|
1338
|
+
this.childSessionMap.delete(sessionId);
|
|
1339
|
+
}
|
|
1109
1340
|
// ---- 内部辅助 ----
|
|
1110
1341
|
createEvent(sessionId, event) {
|
|
1111
1342
|
return { ...event, timestamp: Date.now(), sessionId };
|