foliko 1.1.71 → 1.1.72
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.js
CHANGED
|
@@ -59,7 +59,8 @@ const markdownTheme = {
|
|
|
59
59
|
strikethrough: (text) => chalk.strikethrough(text),
|
|
60
60
|
underline: (text) => chalk.underline(text),
|
|
61
61
|
highlightCode: (code, lang) => {
|
|
62
|
-
const
|
|
62
|
+
const language = lang && hl.supportsLanguage(lang) ? lang : 'text';
|
|
63
|
+
const highlighted = hl.highlight(code, { language, theme: 'nord' });
|
|
63
64
|
return highlighted.split('\n');
|
|
64
65
|
},
|
|
65
66
|
codeBlockIndent: "",
|
|
@@ -191,13 +192,13 @@ class ChatUI {
|
|
|
191
192
|
ERROR: 'red',
|
|
192
193
|
}
|
|
193
194
|
// 监听错误日志,显示到 tooler
|
|
194
|
-
this._logHandler = (data) => {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
};
|
|
200
|
-
logger.on('log', this._logHandler);
|
|
195
|
+
// this._logHandler = (data) => {
|
|
196
|
+
// if(!Object.keys(level_dict).includes(data.level))return;
|
|
197
|
+
// const level=folikoTerracotta(`[${data.level}]`)
|
|
198
|
+
// const level_key=level_dict[data.level]||'dim'
|
|
199
|
+
// this.statusBar.notifier.show(`${level} ${chalk[level_key](data.message)}`)
|
|
200
|
+
// };
|
|
201
|
+
// logger.on('log', this._logHandler);
|
|
201
202
|
|
|
202
203
|
// 监听通知事件,显示到通知区域
|
|
203
204
|
this._notificationHandler = (data) => {
|
|
@@ -246,10 +247,10 @@ class ChatUI {
|
|
|
246
247
|
clearTimeout(this._streamBufferTimer);
|
|
247
248
|
this._streamBufferTimer = null;
|
|
248
249
|
}
|
|
249
|
-
if (this._logHandler && this.agent.framework) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
250
|
+
// if (this._logHandler && this.agent.framework) {
|
|
251
|
+
// logger.off('log', this._logHandler);
|
|
252
|
+
// this._logHandler = null;
|
|
253
|
+
// }
|
|
253
254
|
if (this._notificationHandler && this.agent.framework) {
|
|
254
255
|
this.agent.framework.off('notification', this._notificationHandler);
|
|
255
256
|
this._notificationHandler = null;
|
|
@@ -283,6 +284,7 @@ class ChatUI {
|
|
|
283
284
|
queue.add(function(){
|
|
284
285
|
var next = this.next;
|
|
285
286
|
self.agent.sendMessage(message, { sessionId:self.sessionId }).then(next).catch(function(e){
|
|
287
|
+
self.create_message(chalk.red(`[错误] ${e?.message || e || '发送消息失败'}\n`), colored('● ', RED))
|
|
286
288
|
self.clear_message_done();
|
|
287
289
|
});
|
|
288
290
|
})
|
|
@@ -659,7 +661,7 @@ class ChatUI {
|
|
|
659
661
|
this._streamBufferTimer = setTimeout(() => this._flushStreamBuffer(), 0);
|
|
660
662
|
}
|
|
661
663
|
} else if (chunk.type === 'tool-call') {
|
|
662
|
-
const args = chunk.input ? JSON.stringify(chunk.input).slice(0,
|
|
664
|
+
const args = chunk.input ? JSON.stringify(chunk.input).slice(0, 30) : '';
|
|
663
665
|
this.statusBar.tooler.show(`${chalk.yellow('[Tool]')} ${folikoGold(chunk.toolName)} ${chalk.gray(args+'...')}`)
|
|
664
666
|
} else if(chunk.type==='tool-result'){
|
|
665
667
|
const result = chunk.result;
|
package/package.json
CHANGED
|
@@ -159,7 +159,7 @@ class ExtensionExecutorPlugin extends Plugin {
|
|
|
159
159
|
if (plugin === 'mcp' && this._mcpExecutor) {
|
|
160
160
|
const mcpToolDef = this._mcpExecutor.tools?.[tool];
|
|
161
161
|
if (mcpToolDef && mcpToolDef.execute) {
|
|
162
|
-
log.info(` ext_call [MCP]: tool=${tool}`);
|
|
162
|
+
//log.info(` ext_call [MCP]: tool=${tool}`);
|
|
163
163
|
return await mcpToolDef.execute(toolArgs || {});
|
|
164
164
|
}
|
|
165
165
|
return { success: false, error: `MCP tool '${tool}' not found` };
|
|
@@ -10,6 +10,39 @@ const { logger } = require('../utils/logger');
|
|
|
10
10
|
const log = logger.child('SkillManager');
|
|
11
11
|
const { z } = require('zod');
|
|
12
12
|
const { Command } = require('commander');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 简单的 shell 参数解析器(处理带引号的参数)
|
|
16
|
+
* @param {string} str - 参数字符串
|
|
17
|
+
* @returns {string[]} 参数数组
|
|
18
|
+
*/
|
|
19
|
+
function parseShellArgs(str) {
|
|
20
|
+
if (!str || !str.trim()) return [];
|
|
21
|
+
const args = [];
|
|
22
|
+
let current = '';
|
|
23
|
+
let inQuote = false;
|
|
24
|
+
let quoteChar = '';
|
|
25
|
+
|
|
26
|
+
for (let i = 0; i < str.length; i++) {
|
|
27
|
+
const char = str[i];
|
|
28
|
+
if (!inQuote && (char === '"' || char === "'")) {
|
|
29
|
+
inQuote = true;
|
|
30
|
+
quoteChar = char;
|
|
31
|
+
} else if (inQuote && char === quoteChar) {
|
|
32
|
+
inQuote = false;
|
|
33
|
+
} else if (!inQuote && char === ' ') {
|
|
34
|
+
if (current.trim()) {
|
|
35
|
+
args.push(current.trim());
|
|
36
|
+
current = '';
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
current += char;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (current.trim()) args.push(current.trim());
|
|
43
|
+
return args;
|
|
44
|
+
}
|
|
45
|
+
|
|
13
46
|
/**
|
|
14
47
|
* 验证 skill 名称
|
|
15
48
|
* 1-64字符,字母数字、下划线和连字符,不能以连字符或下划线开头或结尾
|
|
@@ -185,14 +218,20 @@ class Skill {
|
|
|
185
218
|
let argumentParser = cmd.argumentParser;
|
|
186
219
|
if (!argumentParser && Array.isArray(cmd.options) && cmd.options.length > 0) {
|
|
187
220
|
argumentParser = (rawArgs) => {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
program.
|
|
221
|
+
try {
|
|
222
|
+
const program = new Command();
|
|
223
|
+
program.exitOverride(); // 不自动退出
|
|
224
|
+
program.configureOutput({ writeErr: () => {} }); // 隐藏错误输出
|
|
225
|
+
for (const opt of cmd.options) {
|
|
226
|
+
program.option(opt.flags, opt.description, opt.defaultValue);
|
|
227
|
+
}
|
|
228
|
+
program.arguments('[args...]');
|
|
229
|
+
program.parse(['node', 'cmd', ...parseShellArgs(rawArgs)]);
|
|
230
|
+
return { ...program.opts(), args: program.args };
|
|
231
|
+
} catch (err) {
|
|
232
|
+
log.warn(`[SkillManager] Command parse error: ${err.message}`);
|
|
233
|
+
return { args: rawArgs };
|
|
192
234
|
}
|
|
193
|
-
program.arguments('[args...]');
|
|
194
|
-
program.parse(['node', 'cmd', ...(rawArgs || '').split(' ').filter(Boolean)]);
|
|
195
|
-
return { ...program.opts(), args: program.args };
|
|
196
235
|
};
|
|
197
236
|
}
|
|
198
237
|
|
package/src/core/agent-chat.js
CHANGED
|
@@ -500,6 +500,8 @@ class AgentChatHandler extends EventEmitter {
|
|
|
500
500
|
const stream = result.fullStream;
|
|
501
501
|
let fullText = '';
|
|
502
502
|
const iterator = stream[Symbol.asyncIterator] ? stream : stream.fullStream;
|
|
503
|
+
// 追踪发送的 tool-call ID,过滤 API 返回的不匹配 tool-result
|
|
504
|
+
const sentToolCallIds = new Set();
|
|
503
505
|
|
|
504
506
|
for await (const part of iterator || stream) {
|
|
505
507
|
if (part.type === 'text-delta') {
|
|
@@ -510,8 +512,16 @@ class AgentChatHandler extends EventEmitter {
|
|
|
510
512
|
reasoningContent += part.text || '';
|
|
511
513
|
yield { type: 'thinking', text: part.text };
|
|
512
514
|
} else if (part.type === 'tool-call') {
|
|
515
|
+
const toolCallId = part.toolCallId;
|
|
516
|
+
if (toolCallId) sentToolCallIds.add(toolCallId);
|
|
513
517
|
yield { type: 'tool-call', toolName: part.toolName, input: part.input };
|
|
514
518
|
} else if (part.type === 'tool-result') {
|
|
519
|
+
// 过滤 toolCallId 不匹配的 tool-result(API bug)
|
|
520
|
+
const resultToolCallId = part.toolCallId;
|
|
521
|
+
if (resultToolCallId && !sentToolCallIds.has(resultToolCallId)) {
|
|
522
|
+
logger.debug(`[stream]过滤不匹配的 tool-result: ${resultToolCallId}`);
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
515
525
|
yield { type: 'tool-result', toolName: part.toolName, result: part.output };
|
|
516
526
|
} else if (part.type === 'error') {
|
|
517
527
|
// 统一错误消息
|