foliko 1.0.62 → 1.0.63
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 +142 -142
- package/cli/src/commands/chat.js +4 -1
- 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/package.json +1 -1
- package/plugins/ai-plugin.js +2 -1
- package/plugins/ambient-agent-plugin.js +1059 -844
- package/plugins/email.js +122 -1
- package/src/core/agent.js +1 -1
- package/src/core/framework.js +3 -3
- package/src/executors/executor-base.js +58 -58
- package/test-server.js +25 -25
- package/test.txt +3 -3
package/plugins/email.js
CHANGED
|
@@ -188,6 +188,126 @@ class EmailPlugin extends Plugin {
|
|
|
188
188
|
return this._handleEmailWatch(args)
|
|
189
189
|
}
|
|
190
190
|
})
|
|
191
|
+
|
|
192
|
+
// 自动回复邮件
|
|
193
|
+
// this._framework.registerTool({
|
|
194
|
+
// name: 'email_auto_reply',
|
|
195
|
+
// description: '自动分析邮件内容并发送回复(无需用户确认)',
|
|
196
|
+
// inputSchema: z.object({
|
|
197
|
+
// to: z.string().describe('收件人邮箱地址'),
|
|
198
|
+
// subject: z.string().describe('原始邮件主题'),
|
|
199
|
+
// body: z.string().describe('原始邮件内容'),
|
|
200
|
+
// from: z.string().optional().describe('发件人邮箱地址(可选)'),
|
|
201
|
+
// prompt: z.string().optional().describe('自定义提示词,用于指导AI生成回复内容')
|
|
202
|
+
// }),
|
|
203
|
+
// execute: async (args) => {
|
|
204
|
+
// return this._handleAutoReply(args)
|
|
205
|
+
// }
|
|
206
|
+
// })
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* 处理自动回复
|
|
211
|
+
*/
|
|
212
|
+
async _handleAutoReply(args) {
|
|
213
|
+
let { to, subject, body, from, _event, prompt } = args
|
|
214
|
+
|
|
215
|
+
// 如果没有直接参数,尝试从 _event 提取
|
|
216
|
+
if (!to && !subject && !body && _event) {
|
|
217
|
+
const email = _event.data?.email || _event.email || {}
|
|
218
|
+
from = email.from?.text || email.from || ''
|
|
219
|
+
to = email.to?.text || email.to || ''
|
|
220
|
+
subject = email.subject || ''
|
|
221
|
+
body = email.text || email.body || ''
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// 检查必要参数
|
|
225
|
+
if (!from && !to) {
|
|
226
|
+
return { success: false, error: '缺少收件人地址' }
|
|
227
|
+
}
|
|
228
|
+
if (!body) {
|
|
229
|
+
return { success: false, error: '缺少邮件内容' }
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
// 获取活跃的 Agent
|
|
234
|
+
const agent = this._getActiveAgent()
|
|
235
|
+
if (!agent) {
|
|
236
|
+
return { success: false, error: 'No active agent found' }
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// 构建提示让 LLM 生成回复
|
|
240
|
+
const finalPrompt = prompt || `你是一封邮件自动回复助手。请根据以下邮件内容,生成一封专业的回复邮件。
|
|
241
|
+
|
|
242
|
+
【原始邮件】
|
|
243
|
+
发件人: ${from || to}
|
|
244
|
+
主题: ${subject}
|
|
245
|
+
内容:
|
|
246
|
+
${body}
|
|
247
|
+
|
|
248
|
+
【要求】
|
|
249
|
+
1. 回复内容要针对邮件中的问题或内容进行回复
|
|
250
|
+
2. 语言要专业、礼貌、简洁
|
|
251
|
+
3. 只输出邮件正文内容,不要额外解释
|
|
252
|
+
4. 回复语言应与原邮件一致(如果原邮件是中文,则用中文回复)`
|
|
253
|
+
|
|
254
|
+
// 等待 Agent 生成回复(带超时保护)
|
|
255
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
256
|
+
setTimeout(() => reject(new Error('AI回复生成超时(30秒)')), 30000)
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
const replyPromise = agent.pushMessage(finalPrompt, { maxSteps: 3 })
|
|
260
|
+
const replyResult = await Promise.race([replyPromise, timeoutPromise])
|
|
261
|
+
|
|
262
|
+
// 提取回复内容
|
|
263
|
+
let replyContent = ''
|
|
264
|
+
if (typeof replyResult === 'string') {
|
|
265
|
+
replyContent = replyResult.trim()
|
|
266
|
+
} else if (replyResult && replyResult.content) {
|
|
267
|
+
replyContent = replyResult.content.trim()
|
|
268
|
+
} else if (replyResult && replyResult.message) {
|
|
269
|
+
replyContent = replyResult.message.trim()
|
|
270
|
+
} else {
|
|
271
|
+
replyContent = JSON.stringify(replyResult).trim()
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// 去掉思考过程标签
|
|
275
|
+
replyContent = replyContent.replace(/<think>[\s\S]*?<\/think>/g, '').trim()
|
|
276
|
+
|
|
277
|
+
if (!replyContent || replyContent.length < 5) {
|
|
278
|
+
return { success: false, error: 'AI未能生成有效的回复内容' }
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// 发送回复邮件
|
|
282
|
+
const sendResult = await this._sendEmail({
|
|
283
|
+
to: from || to,
|
|
284
|
+
subject: `Re: ${subject}`,
|
|
285
|
+
body: replyContent
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
if (sendResult.success) {
|
|
289
|
+
return {
|
|
290
|
+
success: true,
|
|
291
|
+
message: `自动回复已发送至 ${from || to}`,
|
|
292
|
+
replyContent
|
|
293
|
+
}
|
|
294
|
+
} else {
|
|
295
|
+
return { success: false, error: sendResult.error || '发送失败' }
|
|
296
|
+
}
|
|
297
|
+
} catch (err) {
|
|
298
|
+
return { success: false, error: err.message }
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* 获取活跃的 Agent
|
|
304
|
+
*/
|
|
305
|
+
_getActiveAgent() {
|
|
306
|
+
if (this._framework._mainAgent) {
|
|
307
|
+
return this._framework._mainAgent
|
|
308
|
+
}
|
|
309
|
+
const agents = this._framework._agents || []
|
|
310
|
+
return agents.length > 0 ? agents[agents.length - 1] : null
|
|
191
311
|
}
|
|
192
312
|
|
|
193
313
|
/**
|
|
@@ -201,6 +321,7 @@ class EmailPlugin extends Plugin {
|
|
|
201
321
|
user: process.env.IMAP_USER,
|
|
202
322
|
password: process.env.IMAP_PASS
|
|
203
323
|
}
|
|
324
|
+
|
|
204
325
|
const { action, interval, host, port, user, password, box } = args
|
|
205
326
|
|
|
206
327
|
switch (action) {
|
|
@@ -393,7 +514,7 @@ class EmailPlugin extends Plugin {
|
|
|
393
514
|
// 发送事件通知
|
|
394
515
|
this._emitEmailReceived(email)
|
|
395
516
|
|
|
396
|
-
|
|
517
|
+
console.log(`[Email] New email received: ${email.subject}`)
|
|
397
518
|
cleanup()
|
|
398
519
|
resolve({ success: true, newEmails: newEmails.length, email })
|
|
399
520
|
} else {
|
package/src/core/agent.js
CHANGED
|
@@ -29,7 +29,7 @@ class Agent extends EventEmitter {
|
|
|
29
29
|
this.baseURL = config.baseURL
|
|
30
30
|
this.provider = config.provider || 'deepseek'
|
|
31
31
|
this.providerOptions = config.providerOptions || {}
|
|
32
|
-
|
|
32
|
+
this.providerOptions.maxOutputTokens=8192
|
|
33
33
|
// 原始 system prompt
|
|
34
34
|
this._originalPrompt = config.systemPrompt || '你是一个智能助手。当用户提出问题或任务时,你会主动分析需求,选择合适的工具来获取信息或执行操作。你善于将复杂任务拆解为多个步骤,通过工具协作完成。'
|
|
35
35
|
|
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')
|
|
@@ -223,10 +223,10 @@ class Framework extends EventEmitter {
|
|
|
223
223
|
agentConfig.apiKey = aiPlugin.config.apiKey
|
|
224
224
|
agentConfig.provider = agentConfig.provider || aiPlugin.config.provider
|
|
225
225
|
agentConfig.model = agentConfig.model || aiPlugin.config.model
|
|
226
|
-
agentConfig.baseURL = agentConfig.baseURL || aiPlugin.config.baseURL
|
|
226
|
+
agentConfig.baseURL = agentConfig.baseURL || aiPlugin.config.baseURL,
|
|
227
|
+
agentConfig.providerOptions||aiPlugin.config.providerOptions||{}
|
|
227
228
|
}
|
|
228
229
|
}
|
|
229
|
-
|
|
230
230
|
const agent = new Agent(this, agentConfig)
|
|
231
231
|
this._agents.push(agent)
|
|
232
232
|
|
|
@@ -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
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
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');
|
|
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
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
Hello from static resource test!
|
|
2
|
-
This is a test file for verifying static resource serving.
|
|
3
|
-
Timestamp: 2026-03-24
|
|
1
|
+
Hello from static resource test!
|
|
2
|
+
This is a test file for verifying static resource serving.
|
|
3
|
+
Timestamp: 2026-03-24
|