foliko 1.1.78 → 1.1.80

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.
@@ -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 (input.toLowerCase() === 'exit' || input.toLowerCase() === 'quit') {
150
- console.log('再见!');
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() === '/clean' || input.toLowerCase() === '/clear') {
157
- const { sessionId } = this;
158
- // 清除 AgentChatHandler 的消息存储(需要传 sessionId)
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
- this.interrupted = false;
210
-
211
- const interruptHandler = () => {
212
- if (!this.interrupted) {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foliko",
3
- "version": "1.1.78",
3
+ "version": "1.1.80",
4
4
  "description": "简约的插件化 Agent 框架",
5
5
  "main": "src/index.js",
6
6
  "type": "commonjs",
@@ -378,7 +378,7 @@ class WeixinPlugin extends Plugin {
378
378
  }
379
379
 
380
380
  _on_event_message(){
381
- const {sessionId}=this.ge
381
+ const {sessionId}=this
382
382
  const sessionScope = this.agent.createSessionScope(sessionId);
383
383
  sessionScope.on('stream:chunk', ({ chunk }) => {})
384
384
  }
@@ -388,25 +388,58 @@ class WeixinPlugin extends Plugin {
388
388
  */
389
389
  _setupSessionScopeListeners(agent, sessionId, originalMsg, userId) {
390
390
  const sessionScope = agent.createSessionScope(sessionId)
391
+ const renderState = { inThink: false, inCodeBlock: false };
392
+ const lineBuffer = { value: '' };
393
+
394
+ // 流式文本处理
395
+ sessionScope.on('stream:chunk', ({ chunk }) => {
396
+ if (chunk.type === 'text') {
397
+ lineBuffer.value += chunk.text;
398
+ } else if (chunk.type === 'tool-call') {
399
+ const args = chunk.input ? JSON.stringify(chunk.input).slice(0, 30) : '';
400
+ log.info(`[Tool] ${chunk.toolName} ${args}...`);
401
+ } else if (chunk.type === 'tool-result') {
402
+ const result = chunk.result;
403
+ const shortResult = typeof result === 'string' ? result.slice(0, 30) : JSON.stringify(result).slice(0, 30);
404
+ log.info(`[Tool] ${chunk.toolName} ${shortResult}...`);
405
+ } else if (chunk.type === 'usage') {
406
+ log.debug(`[Usage] input: ${chunk.inputTokens || 0}, output: ${chunk.outputTokens || 0}`);
407
+ }
408
+ });
409
+
410
+ // 消息开始
411
+ sessionScope.on('message:start', async () => {
412
+ this.startTypingInterval();
413
+ });
391
414
 
415
+ // 消息完成
392
416
  sessionScope.on('message:complete', async ({ content }) => {
393
- this.stopTypingInterval()
394
- if (content) {
395
- await this._sendMessageBatch(originalMsg, userId, content, true)
396
- } else {
397
- const msg = '继续进行下一步'
398
- await this._sendMessageBatch(originalMsg, userId, msg, true)
399
- await agent.sendMessage(msg, { sessionId, priority: 1 })
417
+
418
+ if (!content) {
419
+ const msg = '继续进行下一步';
420
+ //await this._sendMessageBatch(originalMsg, userId, msg, true);
421
+ await agent.sendMessage(msg, { sessionId, priority: 1 });
400
422
  }
401
- })
423
+ });
424
+
425
+ // 队列完成
426
+ sessionScope.on('queue:completed', async () => {
427
+ this.stopTypingInterval();
428
+ if (lineBuffer.value.trim()) {
429
+ await this._sendMessageBatch(originalMsg, userId, lineBuffer.value.trim(), true);
430
+ //log.debug(`[Queue] Remaining buffer: ${lineBuffer.value}`);
431
+ }
432
+ lineBuffer.value = '';
433
+ });
402
434
 
435
+ // 队列失败
403
436
  sessionScope.on('queue:failed', async ({ error }) => {
404
- this.stopTypingInterval()
405
- await this._sendMessageBatch(originalMsg, userId, error, true)
406
- })
437
+ this.stopTypingInterval();
438
+ await this._sendMessageBatch(originalMsg, userId, error, true);
439
+ });
407
440
 
408
- this._sessionScopes.set(sessionId, sessionScope)
409
- return sessionScope
441
+ this._sessionScopes.set(sessionId, sessionScope);
442
+ return sessionScope;
410
443
  }
411
444
 
412
445
  /**
@@ -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
@@ -359,7 +359,7 @@ class Subagent extends EventEmitter {
359
359
  messages, // 返回完整消息历史,用于持续对话上下文
360
360
  };
361
361
  } catch (err) {
362
- logger.warn(`[Subagent:${this.name}] generateText error: ${err.message}`);
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 });
@@ -127,12 +127,13 @@ class ChatQueueManager extends EventEmitter {
127
127
 
128
128
  return result;
129
129
  } catch (error) {
130
- log.warn('[ChatQueue] executeWithRetry: ', attempt, 'error:', error.message);
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(''),