foliko 1.0.67 → 1.0.69
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/.claude/settings.local.json +148 -145
- package/examples/basic.js +110 -110
- package/examples/mcp-example.js +53 -53
- package/examples/skill-example.js +49 -49
- package/examples/test-mcp.js +79 -79
- package/examples/test-reload.js +61 -61
- package/news-20260329-1774794949179.html +39 -0
- package/news-20260329-1774794970785.html +39 -0
- package/news-20260329-1774797491928.html +39 -0
- package/package.json +1 -1
- package/plugins/ambient-agent-plugin.js +333 -22
- package/plugins/email.js +106 -20
- package/plugins/feishu-plugin.js +12 -2
- package/plugins/file-system-plugin.js +76 -30
- package/plugins/python-executor-plugin.js +41 -8
- package/plugins/scheduler-plugin.js +14 -11
- package/plugins/telegram-plugin.js +51 -23
- package/plugins/web-plugin.js +8 -6
- package/plugins/weixin-plugin.js +12 -2
- package/skills/ambient-agent/SKILL.md +84 -14
- package/skills/workflow-guide/SKILL.md +214 -2
- package/skills/workflow-troubleshooting/DEBUGGING.md +182 -0
- package/skills/workflow-troubleshooting/SKILL.md +314 -0
- package/src/capabilities/workflow-engine.js +367 -22
- package/src/core/agent-chat.js +106 -14
- package/src/core/framework.js +81 -1
- package/src/executors/executor-base.js +58 -58
- package/test-server.js +0 -25
- package/test.txt +0 -3
package/src/core/agent-chat.js
CHANGED
|
@@ -58,6 +58,9 @@ class AgentChatHandler extends EventEmitter {
|
|
|
58
58
|
this._encoder = null
|
|
59
59
|
this._compressionCount = 0 // 压缩次数统计
|
|
60
60
|
|
|
61
|
+
// 工具结果压缩配置
|
|
62
|
+
this._maxToolResultSize = config.maxToolResultSize || 3000 // 工具结果超过此大小则压缩
|
|
63
|
+
|
|
61
64
|
// 初始化编码器
|
|
62
65
|
this._initEncoder()
|
|
63
66
|
}
|
|
@@ -201,15 +204,85 @@ ${conversationText}
|
|
|
201
204
|
3. 不要超过 1000 字
|
|
202
205
|
4. 用中文回复`
|
|
203
206
|
|
|
204
|
-
//
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
207
|
+
// 使用 AI SDK 6.x 的 generateText
|
|
208
|
+
const { generateText } = require('ai')
|
|
209
|
+
const { text } = await generateText({
|
|
210
|
+
model: this._aiClient,
|
|
211
|
+
prompt: summarizePrompt,
|
|
209
212
|
...this.providerOptions
|
|
210
213
|
})
|
|
211
214
|
|
|
212
|
-
return
|
|
215
|
+
return text || '(总结生成失败)'
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* 检查工具结果是否需要压缩
|
|
220
|
+
* @param {any} result - 工具返回结果
|
|
221
|
+
* @returns {boolean}
|
|
222
|
+
* @private
|
|
223
|
+
*/
|
|
224
|
+
_shouldCompressToolResult(result) {
|
|
225
|
+
if (!result || this._maxToolResultSize <= 0) return false
|
|
226
|
+
|
|
227
|
+
// 计算结果的大小
|
|
228
|
+
let size = 0
|
|
229
|
+
if (typeof result === 'string') {
|
|
230
|
+
size = result.length
|
|
231
|
+
} else if (typeof result === 'object') {
|
|
232
|
+
try {
|
|
233
|
+
size = JSON.stringify(result).length
|
|
234
|
+
} catch {
|
|
235
|
+
size = String(result).length
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return size > this._maxToolResultSize
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* 压缩工具结果
|
|
244
|
+
* @param {any} result - 工具返回结果
|
|
245
|
+
* @returns {Promise<any>} 压缩后的结果
|
|
246
|
+
* @private
|
|
247
|
+
*/
|
|
248
|
+
async _compressToolResult(result) {
|
|
249
|
+
if (!this._shouldCompressToolResult(result)) {
|
|
250
|
+
return result
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (!this._aiClient) {
|
|
254
|
+
console.warn('[AgentChat] Cannot compress tool result: no AI client')
|
|
255
|
+
return result
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
const originalSize = typeof result === 'string' ? result.length : JSON.stringify(result).length
|
|
260
|
+
const resultStr = typeof result === 'string' ? result : JSON.stringify(result, null, 2)
|
|
261
|
+
|
|
262
|
+
// 构建压缩提示
|
|
263
|
+
const compressPrompt = `以下是一个工具执行结果,长度 ${originalSize} 字符。请简洁地总结其核心内容,保留关键数据和信息:
|
|
264
|
+
|
|
265
|
+
${resultStr.substring(0, 8000)}${resultStr.length > 8000 ? '\n...(内容已截断)' : ''}
|
|
266
|
+
|
|
267
|
+
请用简洁的语言总结(不超过 500 字):`
|
|
268
|
+
|
|
269
|
+
// 使用 AI SDK 6.x 的 generateText
|
|
270
|
+
const { generateText } = require('ai')
|
|
271
|
+
const { text } = await generateText({
|
|
272
|
+
model: this._aiClient,
|
|
273
|
+
prompt: compressPrompt,
|
|
274
|
+
...this.providerOptions
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
const summary = text || '(压缩失败,使用原始结果)'
|
|
278
|
+
const compressed = `[工具结果已压缩: 原始大小 ${originalSize} 字符 → ${summary.length} 字符]\n\n${summary}`
|
|
279
|
+
|
|
280
|
+
console.log(`[AgentChat] Tool result compressed: ${originalSize} → ${summary.length} chars`)
|
|
281
|
+
return compressed
|
|
282
|
+
} catch (err) {
|
|
283
|
+
console.warn('[AgentChat] Tool result compression failed:', err.message)
|
|
284
|
+
return result
|
|
285
|
+
}
|
|
213
286
|
}
|
|
214
287
|
|
|
215
288
|
/**
|
|
@@ -280,6 +353,7 @@ ${conversationText}
|
|
|
280
353
|
async chat(message, options = {}) {
|
|
281
354
|
const context = { sessionId: options.sessionId || null, isStream: false }
|
|
282
355
|
const framework = this.agent.framework
|
|
356
|
+
const self = this // 保存引用用于回调
|
|
283
357
|
|
|
284
358
|
// 动态导入 AI SDK
|
|
285
359
|
const { tool, ToolLoopAgent } = await this._importAI()
|
|
@@ -319,7 +393,11 @@ ${conversationText}
|
|
|
319
393
|
return agent.generate({ messages, ...this.providerOptions })
|
|
320
394
|
})
|
|
321
395
|
|
|
322
|
-
|
|
396
|
+
// 处理返回的消息历史:只保留 user 和 assistant 消息,让 SDK 自动处理 tool 消息
|
|
397
|
+
if (result.messages && Array.isArray(result.messages)) {
|
|
398
|
+
// 只保留 user 和 assistant 消息,SDK 会自动维护 tool 消息
|
|
399
|
+
this._messages = result.messages.filter(m => m.role === 'user' || m.role === 'assistant')
|
|
400
|
+
} else if (result.text) {
|
|
323
401
|
this._messages.push({
|
|
324
402
|
role: 'assistant',
|
|
325
403
|
content: result.text
|
|
@@ -366,6 +444,7 @@ ${conversationText}
|
|
|
366
444
|
|
|
367
445
|
const maxSteps = options.maxSteps || this._maxSteps
|
|
368
446
|
const tools = this._getAITools(tool)
|
|
447
|
+
const self = this // 保存引用用于回调
|
|
369
448
|
|
|
370
449
|
if (!this._aiClient) {
|
|
371
450
|
throw new Error('AI client not configured.')
|
|
@@ -391,7 +470,11 @@ ${conversationText}
|
|
|
391
470
|
const stream = result.fullStream
|
|
392
471
|
let fullText = ''
|
|
393
472
|
|
|
394
|
-
|
|
473
|
+
// 流式迭代器
|
|
474
|
+
const iterator = stream[Symbol.asyncIterator] ? stream : stream.fullStream
|
|
475
|
+
const finalMessages = []
|
|
476
|
+
|
|
477
|
+
for await (const part of (iterator || stream)) {
|
|
395
478
|
if (part.type === 'text-delta') {
|
|
396
479
|
const text = part.text || part.textDelta || ''
|
|
397
480
|
fullText += text
|
|
@@ -401,18 +484,27 @@ ${conversationText}
|
|
|
401
484
|
} else if (part.type === 'tool-call') {
|
|
402
485
|
yield { type: 'tool-call', toolName: part.toolName, args: part.input }
|
|
403
486
|
} else if (part.type === 'tool-result') {
|
|
487
|
+
// 保存到临时消息列表
|
|
488
|
+
finalMessages.push({ role: 'tool', content: part.output, toolName: part.toolName })
|
|
404
489
|
yield { type: 'tool-result', toolName: part.toolName, result: part.output }
|
|
405
490
|
} else if (part.type === 'error') {
|
|
406
491
|
yield { type: 'error', error: part.error }
|
|
407
492
|
}
|
|
408
493
|
}
|
|
409
494
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
495
|
+
// 暂时禁用压缩以调试 schema 问题
|
|
496
|
+
// for (const msg of finalMessages) {
|
|
497
|
+
// if (msg.content) {
|
|
498
|
+
// const contentSize = typeof msg.content === 'string' ? msg.content.length : JSON.stringify(msg.content).length
|
|
499
|
+
// if (contentSize > self._maxToolResultSize) {
|
|
500
|
+
// msg.content = await self._compressToolResult(msg.content)
|
|
501
|
+
// }
|
|
502
|
+
// }
|
|
503
|
+
// }
|
|
504
|
+
|
|
505
|
+
// 只保留 user 和 assistant 消息,让 SDK 自动处理 tool 消息
|
|
506
|
+
const assistantMsg = { role: 'assistant', content: fullText }
|
|
507
|
+
this._messages.push(assistantMsg)
|
|
416
508
|
} catch (err) {
|
|
417
509
|
this.emit('error', { error: err.message })
|
|
418
510
|
yield { type: 'error', error: err.message }
|
package/src/core/framework.js
CHANGED
|
@@ -215,7 +215,7 @@ class Framework extends EventEmitter {
|
|
|
215
215
|
name: `session_${sessionId}`,
|
|
216
216
|
...config
|
|
217
217
|
}
|
|
218
|
-
|
|
218
|
+
|
|
219
219
|
// 如果没有提供 AI 相关参数,从 AI 插件获取
|
|
220
220
|
if (!agentConfig.apiKey) {
|
|
221
221
|
const aiPlugin = this.pluginManager.get('ai')
|
|
@@ -239,6 +239,86 @@ class Framework extends EventEmitter {
|
|
|
239
239
|
return agent
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
/**
|
|
243
|
+
* 创建子Agent(具有独立工具集的轻量级Agent)
|
|
244
|
+
* @param {Object} config - 子Agent配置
|
|
245
|
+
* @param {string} config.name - 子Agent名称
|
|
246
|
+
* @param {string} config.role - 角色描述(用于智能选择)
|
|
247
|
+
* @param {string} [config.description] - 供主Agent理解的描述
|
|
248
|
+
* @param {Object} [config.tools] - 自定义工具 { name: toolDef }
|
|
249
|
+
* @param {string[]} [config.parentTools] - 从父Agent继承的工具名称列表
|
|
250
|
+
* @param {Object} [config.llmConfig] - 独立LLM配置
|
|
251
|
+
* @returns {Agent} 创建的子Agent
|
|
252
|
+
*/
|
|
253
|
+
createSubAgent(config) {
|
|
254
|
+
const {
|
|
255
|
+
name,
|
|
256
|
+
role,
|
|
257
|
+
description = '',
|
|
258
|
+
tools = {},
|
|
259
|
+
parentTools, // 如果不传,默认继承主agent所有工具
|
|
260
|
+
llmConfig = null
|
|
261
|
+
} = config
|
|
262
|
+
|
|
263
|
+
// 构建子Agent配置
|
|
264
|
+
const agentConfig = {
|
|
265
|
+
name: `subagent_${name}`,
|
|
266
|
+
role: role,
|
|
267
|
+
systemPrompt: role, // 使用 role 作为 systemPrompt
|
|
268
|
+
...(llmConfig || {}) // 如果提供了独立LLM配置,合并
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// 如果没有提供 AI 相关参数,从 AI 插件获取
|
|
272
|
+
if (!agentConfig.apiKey) {
|
|
273
|
+
const aiPlugin = this.pluginManager.get('ai')
|
|
274
|
+
if (aiPlugin) {
|
|
275
|
+
agentConfig.apiKey = aiPlugin.config.apiKey
|
|
276
|
+
agentConfig.provider = agentConfig.provider || aiPlugin.config.provider
|
|
277
|
+
agentConfig.model = agentConfig.model || aiPlugin.config.model
|
|
278
|
+
agentConfig.baseURL = agentConfig.baseURL || aiPlugin.config.baseURL
|
|
279
|
+
agentConfig.providerOptions = agentConfig.providerOptions || aiPlugin.config.providerOptions || {}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// 创建 Agent
|
|
284
|
+
const agent = new Agent(this, agentConfig)
|
|
285
|
+
|
|
286
|
+
// 注册自定义工具
|
|
287
|
+
for (const [toolName, toolDef] of Object.entries(tools)) {
|
|
288
|
+
if (toolDef && typeof toolDef === 'object') {
|
|
289
|
+
agent.registerTool({
|
|
290
|
+
name: toolName,
|
|
291
|
+
description: toolDef.description || '',
|
|
292
|
+
inputSchema: toolDef.inputSchema,
|
|
293
|
+
execute: toolDef.execute
|
|
294
|
+
})
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// 从父Agent继承工具
|
|
299
|
+
if (this._mainAgent) {
|
|
300
|
+
const parentToolsDefs = this._mainAgent.getTools()
|
|
301
|
+
if (parentTools === undefined) {
|
|
302
|
+
// 如果没有指定 parentTools,默认继承所有工具
|
|
303
|
+
for (const toolDef of parentToolsDefs) {
|
|
304
|
+
agent.registerTool(toolDef)
|
|
305
|
+
}
|
|
306
|
+
} else if (Array.isArray(parentTools) && parentTools.length > 0) {
|
|
307
|
+
// 指定了要继承的工具列表
|
|
308
|
+
for (const toolName of parentTools) {
|
|
309
|
+
const toolDef = parentToolsDefs.find(t => t.name === toolName)
|
|
310
|
+
if (toolDef) {
|
|
311
|
+
agent.registerTool(toolDef)
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
this._agents.push(agent)
|
|
318
|
+
this.emit('agent:created', agent)
|
|
319
|
+
return agent
|
|
320
|
+
}
|
|
321
|
+
|
|
242
322
|
/**
|
|
243
323
|
* 获取 AI 插件
|
|
244
324
|
* @returns {Object|undefined}
|
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Executor 基类
|
|
3
|
-
* 执行器的基类,定义执行器接口
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const { EventEmitter } = require('../utils/event-emitter')
|
|
7
|
-
|
|
8
|
-
class ExecutorBase extends EventEmitter {
|
|
9
|
-
/**
|
|
10
|
-
* @param {string} name - 执行器名称
|
|
11
|
-
*/
|
|
12
|
-
constructor(name) {
|
|
13
|
-
super()
|
|
14
|
-
this.name = name
|
|
15
|
-
this._enabled = true
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* 执行
|
|
20
|
-
* @param {Object} params - 执行参数
|
|
21
|
-
* @returns {Promise<any>}
|
|
22
|
-
*/
|
|
23
|
-
async execute(params) {
|
|
24
|
-
throw new Error('execute() must be implemented')
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* 启用执行器
|
|
29
|
-
*/
|
|
30
|
-
enable() {
|
|
31
|
-
this._enabled = true
|
|
32
|
-
return this
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* 禁用执行器
|
|
37
|
-
*/
|
|
38
|
-
disable() {
|
|
39
|
-
this._enabled = false
|
|
40
|
-
return this
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* 是否启用
|
|
45
|
-
*/
|
|
46
|
-
isEnabled() {
|
|
47
|
-
return this._enabled
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 销毁
|
|
52
|
-
*/
|
|
53
|
-
destroy() {
|
|
54
|
-
this.removeAllListeners()
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
module.exports = { ExecutorBase }
|
|
1
|
+
/**
|
|
2
|
+
* Executor 基类
|
|
3
|
+
* 执行器的基类,定义执行器接口
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { EventEmitter } = require('../utils/event-emitter')
|
|
7
|
+
|
|
8
|
+
class ExecutorBase extends EventEmitter {
|
|
9
|
+
/**
|
|
10
|
+
* @param {string} name - 执行器名称
|
|
11
|
+
*/
|
|
12
|
+
constructor(name) {
|
|
13
|
+
super()
|
|
14
|
+
this.name = name
|
|
15
|
+
this._enabled = true
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 执行
|
|
20
|
+
* @param {Object} params - 执行参数
|
|
21
|
+
* @returns {Promise<any>}
|
|
22
|
+
*/
|
|
23
|
+
async execute(params) {
|
|
24
|
+
throw new Error('execute() must be implemented')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 启用执行器
|
|
29
|
+
*/
|
|
30
|
+
enable() {
|
|
31
|
+
this._enabled = true
|
|
32
|
+
return this
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 禁用执行器
|
|
37
|
+
*/
|
|
38
|
+
disable() {
|
|
39
|
+
this._enabled = false
|
|
40
|
+
return this
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 是否启用
|
|
45
|
+
*/
|
|
46
|
+
isEnabled() {
|
|
47
|
+
return this._enabled
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 销毁
|
|
52
|
+
*/
|
|
53
|
+
destroy() {
|
|
54
|
+
this.removeAllListeners()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = { ExecutorBase }
|
package/test-server.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
const { serve } = require('@hono/node-server');
|
|
2
|
-
const { Hono } = require('hono');
|
|
3
|
-
|
|
4
|
-
const app = new Hono();
|
|
5
|
-
|
|
6
|
-
// 简单路由
|
|
7
|
-
app.get('/test', (c) => {
|
|
8
|
-
console.log('Handler called');
|
|
9
|
-
return c.json({ message: 'Hello World' });
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
const server = serve({
|
|
13
|
-
fetch: app.fetch,
|
|
14
|
-
port: 3001
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
server.on('request', (req) => {
|
|
18
|
-
console.log('Request:', req.method, req.url);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
server.on('error', (err) => {
|
|
22
|
-
console.error('Server error:', err);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
console.log('Server started on port 3001');
|
package/test.txt
DELETED