foliko 1.1.78 → 1.1.79
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/cli/src/ui/chat-ui-old.js +299 -101
- package/package.json +1 -1
- package/src/core/agent-chat.js +1 -1
- package/src/core/subagent.js +2 -2
- package/src/utils/chat-queue.js +4 -3
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
const readline = require('readline');
|
|
7
7
|
const { CLEAR_LINE, CYAN, DIM, GREEN, RED, YELLOW, colored } = require('../utils/ansi');
|
|
8
8
|
const { renderLine } = require('../utils/markdown');
|
|
9
|
-
const { cleanResponse } = require('../../../src/utils');
|
|
9
|
+
const { cleanResponse, logger } = require('../../../src/utils');
|
|
10
|
+
const { logEmitter } = require('../../../src/utils/logger');
|
|
11
|
+
const Queue = require('js-queue');
|
|
10
12
|
|
|
11
13
|
class ChatUI {
|
|
12
14
|
constructor(agent, options = {}) {
|
|
@@ -21,6 +23,9 @@ class ChatUI {
|
|
|
21
23
|
this.sessionId = options.sessionId || 'cli_default';
|
|
22
24
|
this.sessionPlugin = null;
|
|
23
25
|
|
|
26
|
+
// 队列系统
|
|
27
|
+
this.queue = new Queue();
|
|
28
|
+
|
|
24
29
|
// 中断状态(供监听器访问)
|
|
25
30
|
this.interrupted = false;
|
|
26
31
|
|
|
@@ -30,6 +35,15 @@ class ChatUI {
|
|
|
30
35
|
// 流式输出缓冲区(可重置)
|
|
31
36
|
this._lineBuffer = '';
|
|
32
37
|
|
|
38
|
+
// 基础命令
|
|
39
|
+
this.baseCommands = [
|
|
40
|
+
{ name: "compress", description: "压缩记录" },
|
|
41
|
+
{ name: "clear", description: "清除记录" },
|
|
42
|
+
{ name: "exit", description: "退出" },
|
|
43
|
+
{ name: "help", description: "显示帮助信息" },
|
|
44
|
+
{ name: "reload", description: "重载技能" },
|
|
45
|
+
];
|
|
46
|
+
|
|
33
47
|
// 如果 agent 有 framework,获取 SessionPlugin
|
|
34
48
|
if (agent.framework) {
|
|
35
49
|
this.sessionPlugin = agent.framework.pluginManager.get('session');
|
|
@@ -42,6 +56,246 @@ class ChatUI {
|
|
|
42
56
|
// 创建 session scope 并设置监听器(只需一次)
|
|
43
57
|
this.sessionScope = this.agent.createSessionScope(this.sessionId);
|
|
44
58
|
this._setupSessionListeners();
|
|
59
|
+
this._setupFrameworkListeners();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 清理监听器
|
|
65
|
+
*/
|
|
66
|
+
dispose() {
|
|
67
|
+
if (this._logHandler && this.agent.framework) {
|
|
68
|
+
logger.off('log', this._logHandler);
|
|
69
|
+
this._logHandler = null;
|
|
70
|
+
}
|
|
71
|
+
if (this._notificationHandler && this.agent.framework) {
|
|
72
|
+
this.agent.framework.off('notification', this._notificationHandler);
|
|
73
|
+
this._notificationHandler = null;
|
|
74
|
+
}
|
|
75
|
+
if (this._usageHandler && this.agent.framework) {
|
|
76
|
+
this.agent.framework.off('agent:usage', this._usageHandler);
|
|
77
|
+
this._usageHandler = null;
|
|
78
|
+
}
|
|
79
|
+
if (this._skillReloadedHandler && this.agent.framework) {
|
|
80
|
+
this.agent.framework.off('skill:reloaded', this._skillReloadedHandler);
|
|
81
|
+
this._skillReloadedHandler = null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 设置 framework 事件监听(日志、通知、Usage、热重载)
|
|
87
|
+
*/
|
|
88
|
+
_setupFrameworkListeners() {
|
|
89
|
+
const levelDict = {
|
|
90
|
+
DEBUG: 'cyan',
|
|
91
|
+
INFO: 'dim',
|
|
92
|
+
LOG: 'dim',
|
|
93
|
+
WARN: 'yellow',
|
|
94
|
+
ERROR: 'red',
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// 日志监听
|
|
98
|
+
this._logHandler = (data) => {
|
|
99
|
+
if (!Object.keys(levelDict).includes(data.level)) return;
|
|
100
|
+
const level = `[${data.level}]`;
|
|
101
|
+
const levelKey = levelDict[data.level] || 'dim';
|
|
102
|
+
console.log(colored(level, RED) + colored(data.message, levelKey));
|
|
103
|
+
};
|
|
104
|
+
logger.on('log', this._logHandler);
|
|
105
|
+
|
|
106
|
+
// 通知监听
|
|
107
|
+
this._notificationHandler = (data) => {
|
|
108
|
+
if (data.sessionId && data.sessionId !== this.sessionId) return;
|
|
109
|
+
const time = data.timestamp ? new Date(data.timestamp).toLocaleTimeString('zh-CN') : '';
|
|
110
|
+
const notificationText = `[通知] ${data.title}${time ? ` (${time})` : ''}`;
|
|
111
|
+
console.log(colored(notificationText, CYAN));
|
|
112
|
+
if (data.message) {
|
|
113
|
+
console.log(colored(data.message, DIM));
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
this.agent.framework.on('notification', this._notificationHandler);
|
|
117
|
+
|
|
118
|
+
// Usage 监听
|
|
119
|
+
this._usageHandler = (data) => {
|
|
120
|
+
if (data.usage) {
|
|
121
|
+
const u = data.usage;
|
|
122
|
+
const input = u.promptTokens || u.prompt_tokens || 0;
|
|
123
|
+
const output = u.completionTokens || u.completion_tokens || 0;
|
|
124
|
+
// 更新 footerBar 如果存在
|
|
125
|
+
if (this.footerBar) {
|
|
126
|
+
this.footerBar.updateUsage(input, output);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
this.agent.framework.on('agent:usage', this._usageHandler);
|
|
131
|
+
|
|
132
|
+
// Skill 热重载监听
|
|
133
|
+
this._skillReloadedHandler = () => {
|
|
134
|
+
console.log(colored('[提示] 技能已重载', CYAN));
|
|
135
|
+
};
|
|
136
|
+
this.agent.framework.on('skill:reloaded', this._skillReloadedHandler);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* 统一命令执行入口
|
|
141
|
+
*/
|
|
142
|
+
async _executeCommand(trimmed) {
|
|
143
|
+
const cmd = trimmed.toLowerCase();
|
|
144
|
+
|
|
145
|
+
// 基础命令
|
|
146
|
+
if (cmd === '/clear' || cmd === '/clean') {
|
|
147
|
+
this._clearContext();
|
|
148
|
+
console.log(colored('[提示] 对话上下文已清除', CYAN));
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
if (cmd === '/compress') {
|
|
152
|
+
await this._compressContext();
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
if (cmd === '/exit') {
|
|
156
|
+
console.log(colored('[再见] 感谢使用 Foliko!', CYAN));
|
|
157
|
+
this.rl?.close();
|
|
158
|
+
setTimeout(() => process.exit(0), 500);
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
if (cmd === '/help') {
|
|
162
|
+
await this._showHelp();
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
if (cmd === '/reload') {
|
|
166
|
+
await this._reloadSkills();
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Skill 命令 (格式: skillname:cmdname)
|
|
171
|
+
if (trimmed.startsWith('/') && trimmed.includes(':')) {
|
|
172
|
+
const cmdName = trimmed.slice(1).split(' ')[0];
|
|
173
|
+
const cmdArgs = trimmed.slice(cmdName.length + 2);
|
|
174
|
+
try {
|
|
175
|
+
const result = await this.agent.framework.executeTool('ext_call', {
|
|
176
|
+
plugin: 'skill',
|
|
177
|
+
tool: cmdName,
|
|
178
|
+
args: { args: cmdArgs }
|
|
179
|
+
});
|
|
180
|
+
if (result.success !== false) {
|
|
181
|
+
console.log(colored(`[指令] ${cmdName}`, GREEN));
|
|
182
|
+
console.log(result.data || result);
|
|
183
|
+
} else {
|
|
184
|
+
console.log(colored(`[错误] ${result.error || '未知错误'}`, RED));
|
|
185
|
+
}
|
|
186
|
+
} catch (err) {
|
|
187
|
+
console.log(colored(`[错误] ${err.message}`, RED));
|
|
188
|
+
}
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// CommandRegistry 命令
|
|
193
|
+
const { getCommandRegistry } = require('../../../src/core/command-registry');
|
|
194
|
+
const registry = getCommandRegistry();
|
|
195
|
+
const cmdName = trimmed.slice(1).split(' ')[0];
|
|
196
|
+
const cmdArgs = trimmed.slice(cmdName.length + 2);
|
|
197
|
+
if (trimmed.startsWith('/') && cmdName) {
|
|
198
|
+
const cmd = registry.getCommand(cmdName);
|
|
199
|
+
if (cmd) {
|
|
200
|
+
try {
|
|
201
|
+
const context = {
|
|
202
|
+
sessionId: this.sessionId,
|
|
203
|
+
agent: this.agent,
|
|
204
|
+
ui: this,
|
|
205
|
+
framework: this.agent.framework,
|
|
206
|
+
};
|
|
207
|
+
registry.execute(cmdName, cmdArgs, context).catch(err => {
|
|
208
|
+
console.log(colored(`[命令错误] ${err.message}`, RED));
|
|
209
|
+
});
|
|
210
|
+
} catch (err) {
|
|
211
|
+
console.log(colored(`[命令错误] ${err.message}`, RED));
|
|
212
|
+
}
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* 显示帮助信息
|
|
222
|
+
*/
|
|
223
|
+
async _showHelp() {
|
|
224
|
+
const { getCommandRegistry } = require('../../../src/core/command-registry');
|
|
225
|
+
const registry = getCommandRegistry();
|
|
226
|
+
const commands = registry.getAllCommands();
|
|
227
|
+
|
|
228
|
+
console.log(colored('[帮助] 可用命令:', CYAN));
|
|
229
|
+
this.baseCommands.forEach(c => {
|
|
230
|
+
console.log(` ${colored('/' + c.name, CYAN)} - ${c.description}`);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Skill 命令
|
|
234
|
+
const extExecutor = this.agent.framework?.pluginManager?.get('extension-executor');
|
|
235
|
+
if (extExecutor && typeof extExecutor.getSkillCommands === 'function') {
|
|
236
|
+
const skillCommands = extExecutor.getSkillCommands();
|
|
237
|
+
if (skillCommands.length > 0) {
|
|
238
|
+
console.log(colored('\n[技能命令]', CYAN));
|
|
239
|
+
skillCommands.forEach(cmd => {
|
|
240
|
+
console.log(` ${colored('/' + cmd.name, CYAN)} - ${cmd.description || '无描述'}`);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (commands.length > 0) {
|
|
246
|
+
console.log(colored('\n[扩展命令]', CYAN));
|
|
247
|
+
for (const cmd of commands) {
|
|
248
|
+
const pluginTag = cmd.registeredBy ? ` [${cmd.registeredBy}]` : '';
|
|
249
|
+
console.log(` ${colored('/' + cmd.name, CYAN)}${pluginTag} - ${cmd.description || '无描述'}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* 重载技能
|
|
256
|
+
*/
|
|
257
|
+
async _reloadSkills() {
|
|
258
|
+
try {
|
|
259
|
+
const result = await this.agent.framework.executeTool('reloadSkills', {});
|
|
260
|
+
if (result.success !== false) {
|
|
261
|
+
console.log(colored('[提示] 技能已重载', CYAN));
|
|
262
|
+
} else {
|
|
263
|
+
console.log(colored(`[错误] 重载失败: ${result.error}`, RED));
|
|
264
|
+
}
|
|
265
|
+
} catch (err) {
|
|
266
|
+
console.log(colored(`[错误] 重载失败: ${err.message}`, RED));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* 清除上下文
|
|
272
|
+
*/
|
|
273
|
+
_clearContext() {
|
|
274
|
+
const { sessionId } = this;
|
|
275
|
+
this.agent.clearContext(sessionId);
|
|
276
|
+
|
|
277
|
+
if (this.sessionPlugin) {
|
|
278
|
+
const manager = this.sessionPlugin._getSessionManager(sessionId);
|
|
279
|
+
if (manager) manager.clearMessages();
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* 压缩上下文
|
|
285
|
+
*/
|
|
286
|
+
async _compressContext() {
|
|
287
|
+
console.log(colored('[压缩] 压缩中...', YELLOW));
|
|
288
|
+
try {
|
|
289
|
+
const { sessionId } = this;
|
|
290
|
+
const result = await this.agent.compressContext(sessionId);
|
|
291
|
+
console.log(colored(`[压缩] 压缩后: ${result.after} 条 (保留${result.keepRecent}条)`, YELLOW));
|
|
292
|
+
} catch (err) {
|
|
293
|
+
const msg = err.message || String(err);
|
|
294
|
+
if (msg.includes('No messages')) {
|
|
295
|
+
console.log(colored('[提示] 无消息可压缩', CYAN));
|
|
296
|
+
} else {
|
|
297
|
+
console.log(colored(`[错误] ${msg}`, RED));
|
|
298
|
+
}
|
|
45
299
|
}
|
|
46
300
|
}
|
|
47
301
|
|
|
@@ -67,7 +321,39 @@ class ChatUI {
|
|
|
67
321
|
console.log(renderLine(line, renderState));
|
|
68
322
|
}
|
|
69
323
|
}
|
|
324
|
+
} else if (chunk.type === 'tool-call') {
|
|
325
|
+
const args = chunk.input ? JSON.stringify(chunk.input).slice(0, 30) : '';
|
|
326
|
+
console.log(colored(`[Tool] ${chunk.toolName} ${args}...`, YELLOW));
|
|
327
|
+
} else if (chunk.type === 'tool-result') {
|
|
328
|
+
const result = chunk.result;
|
|
329
|
+
const shortResult = typeof result === 'string' ? result.slice(0, 30) : JSON.stringify(result).slice(0, 30);
|
|
330
|
+
console.log(colored(`[Tool] ${chunk.toolName} ${shortResult}...`, GREEN));
|
|
331
|
+
} else if (chunk.type === 'usage') {
|
|
332
|
+
if (this.footerBar) {
|
|
333
|
+
this.footerBar.updateUsage(chunk.inputTokens || 0, chunk.outputTokens || 0);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
this.sessionScope.on('message:start', async () => {
|
|
339
|
+
console.log(colored('● ', GREEN));
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
this.sessionScope.on('message:complete', async ({ content, requestId }) => {
|
|
343
|
+
try {
|
|
344
|
+
if (!content) {
|
|
345
|
+
const msg = '继续';
|
|
346
|
+
await this.agent.sendMessage(msg, { sessionId: this.sessionId, priority: 1 });
|
|
347
|
+
}
|
|
348
|
+
} catch (err) {}
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
this.sessionScope.on('queue:completed', () => {
|
|
352
|
+
// 清理状态
|
|
353
|
+
if (this._lineBuffer.trim() && !this.interrupted) {
|
|
354
|
+
console.log(renderLine(this._lineBuffer, renderState));
|
|
70
355
|
}
|
|
356
|
+
this._lineBuffer = '';
|
|
71
357
|
});
|
|
72
358
|
|
|
73
359
|
this.sessionScope.on('queue:failed', ({ error }) => {
|
|
@@ -145,53 +431,20 @@ class ChatUI {
|
|
|
145
431
|
return;
|
|
146
432
|
}
|
|
147
433
|
|
|
148
|
-
//
|
|
149
|
-
if (
|
|
150
|
-
|
|
151
|
-
this.rl.close();
|
|
434
|
+
// 尝试执行命令
|
|
435
|
+
if (await this._executeCommand(input.trim())) {
|
|
436
|
+
await this.promptUser();
|
|
152
437
|
return;
|
|
153
438
|
}
|
|
154
439
|
|
|
155
|
-
//
|
|
156
|
-
if (input.toLowerCase() === '
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (this.agent._chatSession) {
|
|
160
|
-
this.agent._chatSession.clearSessionMessages(sessionId, true);
|
|
161
|
-
}
|
|
162
|
-
if (this.agent._chatHandler) {
|
|
163
|
-
this.agent._chatHandler.clearHistory(sessionId);
|
|
164
|
-
}
|
|
165
|
-
// 清除 SessionContext 的消息和压缩计数
|
|
166
|
-
if (this.agent.framework) {
|
|
167
|
-
const sessionCtx = this.agent.framework.getSessionContext(sessionId);
|
|
168
|
-
if (sessionCtx) {
|
|
169
|
-
sessionCtx.clearMessages();
|
|
170
|
-
if (sessionCtx.compressionState) {
|
|
171
|
-
sessionCtx.compressionState.count = 0;
|
|
172
|
-
}
|
|
173
|
-
if (sessionCtx.metadata) {
|
|
174
|
-
sessionCtx.metadata.compressionCount = 0;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
// 同步清除 framework 缓存的 sessionContexts
|
|
178
|
-
const cachedCtx = this.agent.framework._sessionContexts?.get(sessionId);
|
|
179
|
-
if (cachedCtx) {
|
|
180
|
-
cachedCtx.clearMessages();
|
|
181
|
-
if (cachedCtx.compressionState) {
|
|
182
|
-
cachedCtx.compressionState.count = 0;
|
|
183
|
-
}
|
|
184
|
-
if (cachedCtx.metadata) {
|
|
185
|
-
cachedCtx.metadata.compressionCount = 0;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
console.log(`${colored('[提示]', CYAN)} 对话上下文已清除\n`);
|
|
190
|
-
await this.promptUser();
|
|
440
|
+
// 退出命令
|
|
441
|
+
if (input.toLowerCase() === 'exit' || input.toLowerCase() === 'quit') {
|
|
442
|
+
console.log(colored('[再见] 感谢使用 Foliko!', CYAN));
|
|
443
|
+
this.rl.close();
|
|
191
444
|
return;
|
|
192
445
|
}
|
|
193
446
|
|
|
194
|
-
//
|
|
447
|
+
// 发送消息(不等待,响应通过事件处理)
|
|
195
448
|
await this.sendMessage(input);
|
|
196
449
|
|
|
197
450
|
// 继续等待下一条消息
|
|
@@ -206,65 +459,10 @@ class ChatUI {
|
|
|
206
459
|
* 发送消息并显示响应
|
|
207
460
|
*/
|
|
208
461
|
async sendMessage(message) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
this.interrupted = true;
|
|
214
|
-
console.log(`\n${colored('[中断]', RED)} 输出已中断`);
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
process.on('SIGINT', interruptHandler);
|
|
219
|
-
|
|
220
|
-
try {
|
|
221
|
-
const { sessionId } = this;
|
|
222
|
-
|
|
223
|
-
if (this.stream) {
|
|
224
|
-
// 流式模式 - 使用已初始化的 sessionScope 监听器
|
|
225
|
-
console.log(colored('● ', GREEN));
|
|
226
|
-
|
|
227
|
-
// 清空缓冲区
|
|
228
|
-
this._lineBuffer = '';
|
|
229
|
-
|
|
230
|
-
// 调用 sendMessage 触发事件
|
|
231
|
-
await this.agent.sendMessage(message, { sessionId });
|
|
232
|
-
|
|
233
|
-
// 输出剩余内容
|
|
234
|
-
if (this._lineBuffer.trim() && !this.interrupted) {
|
|
235
|
-
console.log(renderLine(this._lineBuffer, { inThink: false, inCodeBlock: false }));
|
|
236
|
-
}
|
|
237
|
-
} else {
|
|
238
|
-
// 非流式模式
|
|
239
|
-
console.log(colored('○ ', CYAN) + '处理中...\n');
|
|
240
|
-
|
|
241
|
-
const result = await this.agent.chat(message, { sessionId });
|
|
242
|
-
|
|
243
|
-
if (this.interrupted) return;
|
|
244
|
-
|
|
245
|
-
const lines = result.message.split('\n');
|
|
246
|
-
for (const line of lines) {
|
|
247
|
-
if (line.trim()) {
|
|
248
|
-
console.log(renderLine(line, { inThink: false, inCodeBlock: false }));
|
|
249
|
-
} else {
|
|
250
|
-
console.log();
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
} catch (err) {
|
|
255
|
-
// 只打印简洁错误消息,不打印堆栈
|
|
256
|
-
if (!this.interrupted) {
|
|
257
|
-
const errName = err?.name || '';
|
|
258
|
-
const isRetryError = errName === 'AI_RetryError' || errName === 'RetryError';
|
|
259
|
-
const friendlyMessage = isRetryError
|
|
260
|
-
? 'AI 服务暂时不可用,请稍后重试'
|
|
261
|
-
: (err.message || '未知错误').split('\n')[0];
|
|
262
|
-
|
|
263
|
-
console.error(`\n${colored('[错误]', RED)} ${friendlyMessage}\n`);
|
|
264
|
-
}
|
|
265
|
-
} finally {
|
|
266
|
-
process.removeListener('SIGINT', interruptHandler);
|
|
267
|
-
}
|
|
462
|
+
const self = this;
|
|
463
|
+
const e=await this.agent.sendMessage(message, { sessionId: self.sessionId })
|
|
464
|
+
self._lineBuffer = '';
|
|
465
|
+
// 注意:不等待,直接返回。响应通过 sessionScope 事件处理
|
|
268
466
|
}
|
|
269
467
|
}
|
|
270
468
|
|
package/package.json
CHANGED
package/src/core/agent-chat.js
CHANGED
|
@@ -486,7 +486,7 @@ class AgentChatHandler extends EventEmitter {
|
|
|
486
486
|
|
|
487
487
|
// AI SDK 错误回调:仅记录日志,不在这里处理(统一由 catch/yield 处理)
|
|
488
488
|
const handleSDKError = ({ error }) => {
|
|
489
|
-
logger.debug(`[AgentChat] SDK onError: ${error?.message}`);
|
|
489
|
+
//logger.debug(`[AgentChat] SDK onError: ${error?.message}`);
|
|
490
490
|
};
|
|
491
491
|
|
|
492
492
|
// DeepSeek thinking mode: 收集 reasoning_content
|
package/src/core/subagent.js
CHANGED
|
@@ -359,7 +359,7 @@ class Subagent extends EventEmitter {
|
|
|
359
359
|
messages, // 返回完整消息历史,用于持续对话上下文
|
|
360
360
|
};
|
|
361
361
|
} catch (err) {
|
|
362
|
-
|
|
362
|
+
|
|
363
363
|
lastError = err;
|
|
364
364
|
// 统一使用 retry.js 的错误判断
|
|
365
365
|
if (isNetworkError(err) && attempt < maxRetries) {
|
|
@@ -369,7 +369,7 @@ class Subagent extends EventEmitter {
|
|
|
369
369
|
await new Promise((resolve) => setTimeout(resolve, retryDelay * Math.pow(2, attempt)));
|
|
370
370
|
continue;
|
|
371
371
|
}
|
|
372
|
-
|
|
372
|
+
logger.warn(`[Subagent:${this.name}] generateText error: ${err.message}`);
|
|
373
373
|
// 最终失败,转换为友好消息
|
|
374
374
|
const friendlyMessage = this._getFriendlyError(err);
|
|
375
375
|
this.emit('error', { error: friendlyMessage });
|
package/src/utils/chat-queue.js
CHANGED
|
@@ -127,12 +127,13 @@ class ChatQueueManager extends EventEmitter {
|
|
|
127
127
|
|
|
128
128
|
return result;
|
|
129
129
|
} catch (error) {
|
|
130
|
-
|
|
130
|
+
|
|
131
131
|
lastError = error;
|
|
132
132
|
if (attempt < this.retryAttempts && this.isRetryableError(error)) {
|
|
133
133
|
await this.sleep(calculateDelay(attempt, { baseDelay: this.retryDelay }));
|
|
134
134
|
continue;
|
|
135
135
|
}
|
|
136
|
+
log.warn('[ChatQueue] executeWithRetry: ', attempt, 'error:', error.message);
|
|
136
137
|
break;
|
|
137
138
|
}
|
|
138
139
|
}
|
|
@@ -177,7 +178,7 @@ class ChatQueueManager extends EventEmitter {
|
|
|
177
178
|
? 'AI 服务暂时不可用,请稍后重试'
|
|
178
179
|
: (err.message || err.toString()).split('\n')[0];
|
|
179
180
|
|
|
180
|
-
log.warn('[ChatQueue] executeStream Error:', friendlyMessage);
|
|
181
|
+
//log.warn('[ChatQueue] executeStream Error:', friendlyMessage);
|
|
181
182
|
chunks.push({ type: 'error', error: friendlyMessage });
|
|
182
183
|
this.emit('stream:chunk', {
|
|
183
184
|
requestId: item.id,
|
|
@@ -195,7 +196,7 @@ class ChatQueueManager extends EventEmitter {
|
|
|
195
196
|
const error = new Error(errorChunk.error || 'Stream error');
|
|
196
197
|
error.chunks = chunks;
|
|
197
198
|
error.isStreamError = true;
|
|
198
|
-
log.warn('[ChatQueue] executeStream Error:', error.message);
|
|
199
|
+
//log.warn('[ChatQueue] executeStream Error:', error.message);
|
|
199
200
|
return {
|
|
200
201
|
chunks,
|
|
201
202
|
content: cleanResponse(''),
|