foliko 1.0.75 → 1.0.76
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 +159 -157
- package/cli/bin/foliko.js +12 -12
- package/cli/src/commands/chat.js +143 -143
- package/cli/src/commands/list.js +93 -93
- package/cli/src/index.js +75 -75
- package/cli/src/ui/chat-ui.js +201 -201
- package/cli/src/utils/ansi.js +40 -40
- package/cli/src/utils/markdown.js +292 -292
- package/examples/ambient-example.js +194 -194
- package/examples/basic.js +115 -115
- package/examples/bootstrap.js +121 -121
- package/examples/mcp-example.js +56 -56
- package/examples/skill-example.js +49 -49
- package/examples/test-chat.js +137 -137
- package/examples/test-mcp.js +85 -85
- package/examples/test-reload.js +59 -59
- package/examples/test-telegram.js +50 -50
- package/examples/test-tg-bot.js +45 -45
- package/examples/test-tg-simple.js +47 -47
- package/examples/test-tg.js +62 -62
- package/examples/test-think.js +43 -43
- package/examples/test-web-plugin.js +103 -103
- package/examples/test-weixin-feishu.js +103 -103
- package/examples/workflow.js +158 -158
- package/package.json +1 -1
- package/plugins/ai-plugin.js +102 -102
- package/plugins/ambient-agent/EventWatcher.js +113 -113
- package/plugins/ambient-agent/ExplorerLoop.js +640 -640
- package/plugins/ambient-agent/GoalManager.js +197 -197
- package/plugins/ambient-agent/Reflector.js +95 -95
- package/plugins/ambient-agent/StateStore.js +90 -90
- package/plugins/ambient-agent/constants.js +101 -101
- package/plugins/ambient-agent/index.js +579 -579
- package/plugins/audit-plugin.js +187 -187
- package/plugins/default-plugins.js +662 -662
- package/plugins/email/constants.js +64 -64
- package/plugins/email/handlers.js +461 -461
- package/plugins/email/index.js +278 -278
- package/plugins/email/monitor.js +269 -269
- package/plugins/email/parser.js +138 -138
- package/plugins/email/reply.js +151 -151
- package/plugins/email/utils.js +124 -124
- package/plugins/feishu-plugin.js +481 -481
- package/plugins/file-system-plugin.js +826 -826
- package/plugins/install-plugin.js +199 -199
- package/plugins/python-executor-plugin.js +367 -367
- package/plugins/python-plugin-loader.js +481 -481
- package/plugins/rules-plugin.js +294 -294
- package/plugins/scheduler-plugin.js +691 -691
- package/plugins/session-plugin.js +369 -369
- package/plugins/shell-executor-plugin.js +197 -197
- package/plugins/storage-plugin.js +240 -240
- package/plugins/subagent-plugin.js +845 -845
- package/plugins/telegram-plugin.js +482 -482
- package/plugins/think-plugin.js +345 -345
- package/plugins/tools-plugin.js +196 -196
- package/plugins/web-plugin.js +606 -606
- package/plugins/weixin-plugin.js +545 -545
- package/src/capabilities/index.js +11 -11
- package/src/capabilities/skill-manager.js +609 -609
- package/src/capabilities/workflow-engine.js +1109 -1109
- package/src/core/agent-chat.js +882 -882
- package/src/core/agent.js +892 -892
- package/src/core/framework.js +465 -465
- package/src/core/index.js +19 -19
- package/src/core/plugin-base.js +219 -219
- package/src/core/plugin-manager.js +863 -863
- package/src/core/provider.js +114 -114
- package/src/core/sub-agent-config.js +264 -264
- package/src/core/system-prompt-builder.js +120 -120
- package/src/core/tool-registry.js +517 -517
- package/src/core/tool-router.js +297 -297
- package/src/executors/executor-base.js +58 -58
- package/src/executors/mcp-executor.js +741 -741
- package/src/index.js +25 -25
- package/src/utils/circuit-breaker.js +301 -301
- package/src/utils/error-boundary.js +363 -363
- package/src/utils/error.js +374 -374
- package/src/utils/event-emitter.js +97 -97
- package/src/utils/id.js +133 -133
- package/src/utils/index.js +217 -217
- package/src/utils/logger.js +181 -181
- package/src/utils/plugin-helpers.js +90 -90
- package/src/utils/retry.js +122 -122
- package/src/utils/sandbox.js +292 -292
- package/test/tool-registry-validation.test.js +218 -218
- package/website/script.js +136 -136
- package/foliko-1.0.75.tgz +0 -0
package/plugins/email/index.js
CHANGED
|
@@ -1,278 +1,278 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Email 插件
|
|
3
|
-
* 邮件收发插件 - 支持读取和发送电子邮件、监控新邮件
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const { Plugin } = require('../../src/core/plugin-base')
|
|
7
|
-
const { logger } = require('../../src/utils/logger')
|
|
8
|
-
const log = logger.child('Email')
|
|
9
|
-
const { z } = require('zod')
|
|
10
|
-
|
|
11
|
-
// 导入子模块
|
|
12
|
-
const { sendEmail, readEmails, getUnreadCount, markAsRead, deleteEmail, getEmailConfig } = require('./handlers')
|
|
13
|
-
const { handleEmailWatch } = require('./monitor')
|
|
14
|
-
const { handleAutoReply } = require('./reply')
|
|
15
|
-
const { EMAIL_DEFAULTS } = require('./constants')
|
|
16
|
-
|
|
17
|
-
class EmailPlugin extends Plugin {
|
|
18
|
-
constructor(config = {}) {
|
|
19
|
-
super()
|
|
20
|
-
this.name = 'email'
|
|
21
|
-
this.version = '1.1.0'
|
|
22
|
-
this.description = `邮件收发插件 - 支持读取和发送电子邮件、监控新邮件
|
|
23
|
-
功能:
|
|
24
|
-
- 发送邮件支持附件(本地文件、远程URL、Base64)
|
|
25
|
-
- 读取邮件(IMAP协议)
|
|
26
|
-
- 监控新邮件(支持IMAP IDLE推送和定时轮询)
|
|
27
|
-
发送邮件支持附件:
|
|
28
|
-
- attachments.path: 本地文件路径
|
|
29
|
-
- attachments.url: 远程图片/文件URL(自动下载)
|
|
30
|
-
- attachments.content: Base64内容
|
|
31
|
-
- attachments.cid: 嵌入式图片CID(HTML中用 <img src="cid:xxx"> 引用)`
|
|
32
|
-
this.priority = 10
|
|
33
|
-
this.enabled = false
|
|
34
|
-
|
|
35
|
-
// 邮件监控状态
|
|
36
|
-
this._watchInterval = null
|
|
37
|
-
this._lastSeenUid = null
|
|
38
|
-
this._watchConfig = null
|
|
39
|
-
this._watchEnabled = false
|
|
40
|
-
this._checkInProgress = false
|
|
41
|
-
|
|
42
|
-
// 带上限的 Set,防止内存泄漏
|
|
43
|
-
const MAX_SET_SIZE = 1000
|
|
44
|
-
this._recentlyEmailed = new Set()
|
|
45
|
-
this._processedEmails = new Set()
|
|
46
|
-
this._maxSetSize = MAX_SET_SIZE
|
|
47
|
-
|
|
48
|
-
// 日志器
|
|
49
|
-
this._log = log
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
install(framework) {
|
|
53
|
-
this._framework = framework
|
|
54
|
-
this._registerTools()
|
|
55
|
-
return this
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
start(framework) {
|
|
59
|
-
return this
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* 向 Set 中添加元素,自动控制大小防止内存泄漏
|
|
64
|
-
* @param {Set} set - 要操作的 Set
|
|
65
|
-
* @param {*} item - 要添加的元素
|
|
66
|
-
* @private
|
|
67
|
-
*/
|
|
68
|
-
_addToBoundedSet(set, item) {
|
|
69
|
-
if (set.size >= this._maxSetSize) {
|
|
70
|
-
// 删除最早的元素(Set 的插入顺序)
|
|
71
|
-
const firstKey = set.values().next().value
|
|
72
|
-
set.delete(firstKey)
|
|
73
|
-
}
|
|
74
|
-
set.add(item)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* 发送邮件事件
|
|
79
|
-
*/
|
|
80
|
-
_emitEmailReceived(email) {
|
|
81
|
-
if (!this._framework) return
|
|
82
|
-
|
|
83
|
-
const msgId = email.messageId || email.uid
|
|
84
|
-
|
|
85
|
-
// 优先检查是否已处理过(长TTL,防止服务器标记失败导致重复处理)
|
|
86
|
-
if (msgId && this._processedEmails.has(msgId)) {
|
|
87
|
-
this._log.info(`跳过已处理的邮件: ${email.subject} (${msgId})`)
|
|
88
|
-
return
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// 快速去重(短TTL,防止同一批次重复触发)
|
|
92
|
-
if (msgId && this._recentlyEmailed.has(msgId)) {
|
|
93
|
-
return
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// 标记为已处理
|
|
97
|
-
if (msgId) {
|
|
98
|
-
// 使用 bounded set 防止内存泄漏
|
|
99
|
-
this._addToBoundedSet(this._recentlyEmailed, msgId)
|
|
100
|
-
setTimeout(() => {
|
|
101
|
-
this._recentlyEmailed.delete(msgId)
|
|
102
|
-
}, EMAIL_DEFAULTS.recentlyEmailTTL)
|
|
103
|
-
|
|
104
|
-
// _processedEmails 也需要 bounded
|
|
105
|
-
this._addToBoundedSet(this._processedEmails, msgId)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
this._framework.emit('email:received', {
|
|
109
|
-
email,
|
|
110
|
-
timestamp: new Date()
|
|
111
|
-
})
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
_registerTools() {
|
|
115
|
-
// 发送邮件工具
|
|
116
|
-
this._framework.registerTool({
|
|
117
|
-
name: 'email_send',
|
|
118
|
-
description: '发送电子邮件,无须用户确认',
|
|
119
|
-
inputSchema: z.object({
|
|
120
|
-
to: z.string().describe('收件人邮箱地址'),
|
|
121
|
-
subject: z.string().describe('邮件主题'),
|
|
122
|
-
body: z.string().describe('邮件正文内容'),
|
|
123
|
-
cc: z.string().optional().describe('抄送邮箱地址,多个用逗号分隔'),
|
|
124
|
-
bcc: z.string().optional().describe('密送邮箱地址,多个用逗号分隔'),
|
|
125
|
-
isHtml: z.boolean().optional().describe('是否为HTML格式,默认false'),
|
|
126
|
-
attachments: z.array(z.object({
|
|
127
|
-
filename: z.string().describe('附件文件名'),
|
|
128
|
-
path: z.string().optional().describe('本地文件路径'),
|
|
129
|
-
url: z.string().optional().describe('远程图片URL'),
|
|
130
|
-
content: z.string().optional().describe('Base64编码内容(可带前缀如 data:image/png;base64,)'),
|
|
131
|
-
cid: z.string().optional().describe('嵌入式图片的CID(用于在HTML中嵌入图片,如 <img src="cid:xxx">)')
|
|
132
|
-
})).optional().describe('附件列表,支持本地文件、远程URL或Base64内容')
|
|
133
|
-
}),
|
|
134
|
-
execute: async (args) => {
|
|
135
|
-
return sendEmail(this, args)
|
|
136
|
-
}
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
// 读取邮件工具
|
|
140
|
-
this._framework.registerTool({
|
|
141
|
-
name: 'email_read',
|
|
142
|
-
description: '读取电子邮件(支持IMAP协议)',
|
|
143
|
-
inputSchema: z.object({
|
|
144
|
-
box: z.string().optional().describe('邮箱文件夹,默认INBOX'),
|
|
145
|
-
limit: z.number().optional().describe('读取邮件数量,默认10'),
|
|
146
|
-
unreadOnly: z.boolean().optional().describe('仅读取未读邮件,默认false'),
|
|
147
|
-
searchCriteria: z.string().optional().describe('搜索条件,如 "UNSEEN", "FROM sender@example.com"')
|
|
148
|
-
}),
|
|
149
|
-
execute: async (args) => {
|
|
150
|
-
return readEmails(this, args)
|
|
151
|
-
}
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
// 获取未读邮件数量
|
|
155
|
-
this._framework.registerTool({
|
|
156
|
-
name: 'email_unread_count',
|
|
157
|
-
description: '获取邮箱未读邮件数量',
|
|
158
|
-
inputSchema: z.object({
|
|
159
|
-
box: z.string().optional().describe('邮箱文件夹,默认INBOX')
|
|
160
|
-
}),
|
|
161
|
-
execute: async (args) => {
|
|
162
|
-
return getUnreadCount(this, args)
|
|
163
|
-
}
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
// 标记邮件为已读
|
|
167
|
-
this._framework.registerTool({
|
|
168
|
-
name: 'email_mark_read',
|
|
169
|
-
description: '标记邮件为已读',
|
|
170
|
-
inputSchema: z.object({
|
|
171
|
-
messageId: z.string().describe('邮件UID或序列号')
|
|
172
|
-
}),
|
|
173
|
-
execute: async (args) => {
|
|
174
|
-
return markAsRead(this, args)
|
|
175
|
-
}
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
// 删除邮件
|
|
179
|
-
this._framework.registerTool({
|
|
180
|
-
name: 'email_delete',
|
|
181
|
-
description: '删除邮件(标记为已删除,然后永久删除)',
|
|
182
|
-
inputSchema: z.object({
|
|
183
|
-
messageId: z.string().describe('邮件UID或序列号'),
|
|
184
|
-
box: z.string().optional().describe('邮箱文件夹,默认INBOX')
|
|
185
|
-
}),
|
|
186
|
-
execute: async (args) => {
|
|
187
|
-
return deleteEmail(this, args)
|
|
188
|
-
}
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
// 配置邮箱连接
|
|
192
|
-
this._framework.registerTool({
|
|
193
|
-
name: 'email_configure',
|
|
194
|
-
description: '查看邮箱配置(实际配置通过环境变量设置)',
|
|
195
|
-
inputSchema: z.object({}),
|
|
196
|
-
execute: async () => {
|
|
197
|
-
return getEmailConfig()
|
|
198
|
-
}
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
// 监控新邮件
|
|
202
|
-
this._framework.registerTool({
|
|
203
|
-
name: 'email_watch',
|
|
204
|
-
description: '启动/停止邮件监控,检测新邮件并发送事件通知',
|
|
205
|
-
inputSchema: z.object({
|
|
206
|
-
action: z.enum(['start', 'stop', 'status']).describe('操作:启动监控、停止监控、查看状态'),
|
|
207
|
-
interval: z.number().optional().describe('轮询间隔(秒),默认60秒,适用于不支持IDLE的服务器'),
|
|
208
|
-
box: z.string().optional().describe('邮箱文件夹,默认INBOX')
|
|
209
|
-
}),
|
|
210
|
-
execute: async (args) => {
|
|
211
|
-
return handleEmailWatch(this, args)
|
|
212
|
-
}
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
// 自动回复邮件
|
|
216
|
-
this._framework.registerTool({
|
|
217
|
-
name: 'email_auto_reply',
|
|
218
|
-
description: '自动分析邮件内容并发送回复(无需用户确认)',
|
|
219
|
-
inputSchema: z.object({
|
|
220
|
-
to: z.string().describe('收件人邮箱地址'),
|
|
221
|
-
subject: z.string().describe('原始邮件主题'),
|
|
222
|
-
body: z.string().describe('原始邮件内容'),
|
|
223
|
-
from: z.string().optional().describe('发件人邮箱地址(可选)'),
|
|
224
|
-
prompt: z.string().optional().describe('自定义提示词,用于指导AI生成回复内容'),
|
|
225
|
-
timeout: z.number().optional().describe('AI生成回复超时时间(毫秒),默认60000'),
|
|
226
|
-
messageId: z.string().optional().describe('原始邮件的Message-ID,用于在邮件客户端中创建回复线程')
|
|
227
|
-
}),
|
|
228
|
-
execute: async (args) => {
|
|
229
|
-
return handleAutoReply(this, args)
|
|
230
|
-
}
|
|
231
|
-
})
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* 启动邮件监控(内部方法)
|
|
236
|
-
*/
|
|
237
|
-
_startEmailWatch(config) {
|
|
238
|
-
const { startEmailWatch } = require('./monitor')
|
|
239
|
-
return startEmailWatch(this, config)
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* 停止邮件监控(内部方法)
|
|
244
|
-
*/
|
|
245
|
-
_stopEmailWatch() {
|
|
246
|
-
const { stopEmailWatch } = require('./monitor')
|
|
247
|
-
return stopEmailWatch(this)
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* 获取监控状态(内部方法)
|
|
252
|
-
*/
|
|
253
|
-
_getEmailWatchStatus() {
|
|
254
|
-
const { getEmailWatchStatus } = require('./monitor')
|
|
255
|
-
return getEmailWatchStatus(this)
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* 检查新邮件(内部方法)
|
|
260
|
-
*/
|
|
261
|
-
async _checkNewEmails() {
|
|
262
|
-
const { checkNewEmails } = require('./monitor')
|
|
263
|
-
return checkNewEmails(this)
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
uninstall(framework) {
|
|
267
|
-
// 停止邮件监控
|
|
268
|
-
if (this._watchInterval) {
|
|
269
|
-
clearInterval(this._watchInterval)
|
|
270
|
-
this._watchInterval = null
|
|
271
|
-
}
|
|
272
|
-
this._watchEnabled = false
|
|
273
|
-
this._watchConfig = null
|
|
274
|
-
this._framework = null
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
module.exports = { EmailPlugin }
|
|
1
|
+
/**
|
|
2
|
+
* Email 插件
|
|
3
|
+
* 邮件收发插件 - 支持读取和发送电子邮件、监控新邮件
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { Plugin } = require('../../src/core/plugin-base')
|
|
7
|
+
const { logger } = require('../../src/utils/logger')
|
|
8
|
+
const log = logger.child('Email')
|
|
9
|
+
const { z } = require('zod')
|
|
10
|
+
|
|
11
|
+
// 导入子模块
|
|
12
|
+
const { sendEmail, readEmails, getUnreadCount, markAsRead, deleteEmail, getEmailConfig } = require('./handlers')
|
|
13
|
+
const { handleEmailWatch } = require('./monitor')
|
|
14
|
+
const { handleAutoReply } = require('./reply')
|
|
15
|
+
const { EMAIL_DEFAULTS } = require('./constants')
|
|
16
|
+
|
|
17
|
+
class EmailPlugin extends Plugin {
|
|
18
|
+
constructor(config = {}) {
|
|
19
|
+
super()
|
|
20
|
+
this.name = 'email'
|
|
21
|
+
this.version = '1.1.0'
|
|
22
|
+
this.description = `邮件收发插件 - 支持读取和发送电子邮件、监控新邮件
|
|
23
|
+
功能:
|
|
24
|
+
- 发送邮件支持附件(本地文件、远程URL、Base64)
|
|
25
|
+
- 读取邮件(IMAP协议)
|
|
26
|
+
- 监控新邮件(支持IMAP IDLE推送和定时轮询)
|
|
27
|
+
发送邮件支持附件:
|
|
28
|
+
- attachments.path: 本地文件路径
|
|
29
|
+
- attachments.url: 远程图片/文件URL(自动下载)
|
|
30
|
+
- attachments.content: Base64内容
|
|
31
|
+
- attachments.cid: 嵌入式图片CID(HTML中用 <img src="cid:xxx"> 引用)`
|
|
32
|
+
this.priority = 10
|
|
33
|
+
this.enabled = false
|
|
34
|
+
|
|
35
|
+
// 邮件监控状态
|
|
36
|
+
this._watchInterval = null
|
|
37
|
+
this._lastSeenUid = null
|
|
38
|
+
this._watchConfig = null
|
|
39
|
+
this._watchEnabled = false
|
|
40
|
+
this._checkInProgress = false
|
|
41
|
+
|
|
42
|
+
// 带上限的 Set,防止内存泄漏
|
|
43
|
+
const MAX_SET_SIZE = 1000
|
|
44
|
+
this._recentlyEmailed = new Set()
|
|
45
|
+
this._processedEmails = new Set()
|
|
46
|
+
this._maxSetSize = MAX_SET_SIZE
|
|
47
|
+
|
|
48
|
+
// 日志器
|
|
49
|
+
this._log = log
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
install(framework) {
|
|
53
|
+
this._framework = framework
|
|
54
|
+
this._registerTools()
|
|
55
|
+
return this
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
start(framework) {
|
|
59
|
+
return this
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 向 Set 中添加元素,自动控制大小防止内存泄漏
|
|
64
|
+
* @param {Set} set - 要操作的 Set
|
|
65
|
+
* @param {*} item - 要添加的元素
|
|
66
|
+
* @private
|
|
67
|
+
*/
|
|
68
|
+
_addToBoundedSet(set, item) {
|
|
69
|
+
if (set.size >= this._maxSetSize) {
|
|
70
|
+
// 删除最早的元素(Set 的插入顺序)
|
|
71
|
+
const firstKey = set.values().next().value
|
|
72
|
+
set.delete(firstKey)
|
|
73
|
+
}
|
|
74
|
+
set.add(item)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 发送邮件事件
|
|
79
|
+
*/
|
|
80
|
+
_emitEmailReceived(email) {
|
|
81
|
+
if (!this._framework) return
|
|
82
|
+
|
|
83
|
+
const msgId = email.messageId || email.uid
|
|
84
|
+
|
|
85
|
+
// 优先检查是否已处理过(长TTL,防止服务器标记失败导致重复处理)
|
|
86
|
+
if (msgId && this._processedEmails.has(msgId)) {
|
|
87
|
+
this._log.info(`跳过已处理的邮件: ${email.subject} (${msgId})`)
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 快速去重(短TTL,防止同一批次重复触发)
|
|
92
|
+
if (msgId && this._recentlyEmailed.has(msgId)) {
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 标记为已处理
|
|
97
|
+
if (msgId) {
|
|
98
|
+
// 使用 bounded set 防止内存泄漏
|
|
99
|
+
this._addToBoundedSet(this._recentlyEmailed, msgId)
|
|
100
|
+
setTimeout(() => {
|
|
101
|
+
this._recentlyEmailed.delete(msgId)
|
|
102
|
+
}, EMAIL_DEFAULTS.recentlyEmailTTL)
|
|
103
|
+
|
|
104
|
+
// _processedEmails 也需要 bounded
|
|
105
|
+
this._addToBoundedSet(this._processedEmails, msgId)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
this._framework.emit('email:received', {
|
|
109
|
+
email,
|
|
110
|
+
timestamp: new Date()
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
_registerTools() {
|
|
115
|
+
// 发送邮件工具
|
|
116
|
+
this._framework.registerTool({
|
|
117
|
+
name: 'email_send',
|
|
118
|
+
description: '发送电子邮件,无须用户确认',
|
|
119
|
+
inputSchema: z.object({
|
|
120
|
+
to: z.string().describe('收件人邮箱地址'),
|
|
121
|
+
subject: z.string().describe('邮件主题'),
|
|
122
|
+
body: z.string().describe('邮件正文内容'),
|
|
123
|
+
cc: z.string().optional().describe('抄送邮箱地址,多个用逗号分隔'),
|
|
124
|
+
bcc: z.string().optional().describe('密送邮箱地址,多个用逗号分隔'),
|
|
125
|
+
isHtml: z.boolean().optional().describe('是否为HTML格式,默认false'),
|
|
126
|
+
attachments: z.array(z.object({
|
|
127
|
+
filename: z.string().describe('附件文件名'),
|
|
128
|
+
path: z.string().optional().describe('本地文件路径'),
|
|
129
|
+
url: z.string().optional().describe('远程图片URL'),
|
|
130
|
+
content: z.string().optional().describe('Base64编码内容(可带前缀如 data:image/png;base64,)'),
|
|
131
|
+
cid: z.string().optional().describe('嵌入式图片的CID(用于在HTML中嵌入图片,如 <img src="cid:xxx">)')
|
|
132
|
+
})).optional().describe('附件列表,支持本地文件、远程URL或Base64内容')
|
|
133
|
+
}),
|
|
134
|
+
execute: async (args) => {
|
|
135
|
+
return sendEmail(this, args)
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
// 读取邮件工具
|
|
140
|
+
this._framework.registerTool({
|
|
141
|
+
name: 'email_read',
|
|
142
|
+
description: '读取电子邮件(支持IMAP协议)',
|
|
143
|
+
inputSchema: z.object({
|
|
144
|
+
box: z.string().optional().describe('邮箱文件夹,默认INBOX'),
|
|
145
|
+
limit: z.number().optional().describe('读取邮件数量,默认10'),
|
|
146
|
+
unreadOnly: z.boolean().optional().describe('仅读取未读邮件,默认false'),
|
|
147
|
+
searchCriteria: z.string().optional().describe('搜索条件,如 "UNSEEN", "FROM sender@example.com"')
|
|
148
|
+
}),
|
|
149
|
+
execute: async (args) => {
|
|
150
|
+
return readEmails(this, args)
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
// 获取未读邮件数量
|
|
155
|
+
this._framework.registerTool({
|
|
156
|
+
name: 'email_unread_count',
|
|
157
|
+
description: '获取邮箱未读邮件数量',
|
|
158
|
+
inputSchema: z.object({
|
|
159
|
+
box: z.string().optional().describe('邮箱文件夹,默认INBOX')
|
|
160
|
+
}),
|
|
161
|
+
execute: async (args) => {
|
|
162
|
+
return getUnreadCount(this, args)
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
// 标记邮件为已读
|
|
167
|
+
this._framework.registerTool({
|
|
168
|
+
name: 'email_mark_read',
|
|
169
|
+
description: '标记邮件为已读',
|
|
170
|
+
inputSchema: z.object({
|
|
171
|
+
messageId: z.string().describe('邮件UID或序列号')
|
|
172
|
+
}),
|
|
173
|
+
execute: async (args) => {
|
|
174
|
+
return markAsRead(this, args)
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
// 删除邮件
|
|
179
|
+
this._framework.registerTool({
|
|
180
|
+
name: 'email_delete',
|
|
181
|
+
description: '删除邮件(标记为已删除,然后永久删除)',
|
|
182
|
+
inputSchema: z.object({
|
|
183
|
+
messageId: z.string().describe('邮件UID或序列号'),
|
|
184
|
+
box: z.string().optional().describe('邮箱文件夹,默认INBOX')
|
|
185
|
+
}),
|
|
186
|
+
execute: async (args) => {
|
|
187
|
+
return deleteEmail(this, args)
|
|
188
|
+
}
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
// 配置邮箱连接
|
|
192
|
+
this._framework.registerTool({
|
|
193
|
+
name: 'email_configure',
|
|
194
|
+
description: '查看邮箱配置(实际配置通过环境变量设置)',
|
|
195
|
+
inputSchema: z.object({}),
|
|
196
|
+
execute: async () => {
|
|
197
|
+
return getEmailConfig()
|
|
198
|
+
}
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
// 监控新邮件
|
|
202
|
+
this._framework.registerTool({
|
|
203
|
+
name: 'email_watch',
|
|
204
|
+
description: '启动/停止邮件监控,检测新邮件并发送事件通知',
|
|
205
|
+
inputSchema: z.object({
|
|
206
|
+
action: z.enum(['start', 'stop', 'status']).describe('操作:启动监控、停止监控、查看状态'),
|
|
207
|
+
interval: z.number().optional().describe('轮询间隔(秒),默认60秒,适用于不支持IDLE的服务器'),
|
|
208
|
+
box: z.string().optional().describe('邮箱文件夹,默认INBOX')
|
|
209
|
+
}),
|
|
210
|
+
execute: async (args) => {
|
|
211
|
+
return handleEmailWatch(this, args)
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
// 自动回复邮件
|
|
216
|
+
this._framework.registerTool({
|
|
217
|
+
name: 'email_auto_reply',
|
|
218
|
+
description: '自动分析邮件内容并发送回复(无需用户确认)',
|
|
219
|
+
inputSchema: z.object({
|
|
220
|
+
to: z.string().describe('收件人邮箱地址'),
|
|
221
|
+
subject: z.string().describe('原始邮件主题'),
|
|
222
|
+
body: z.string().describe('原始邮件内容'),
|
|
223
|
+
from: z.string().optional().describe('发件人邮箱地址(可选)'),
|
|
224
|
+
prompt: z.string().optional().describe('自定义提示词,用于指导AI生成回复内容'),
|
|
225
|
+
timeout: z.number().optional().describe('AI生成回复超时时间(毫秒),默认60000'),
|
|
226
|
+
messageId: z.string().optional().describe('原始邮件的Message-ID,用于在邮件客户端中创建回复线程')
|
|
227
|
+
}),
|
|
228
|
+
execute: async (args) => {
|
|
229
|
+
return handleAutoReply(this, args)
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* 启动邮件监控(内部方法)
|
|
236
|
+
*/
|
|
237
|
+
_startEmailWatch(config) {
|
|
238
|
+
const { startEmailWatch } = require('./monitor')
|
|
239
|
+
return startEmailWatch(this, config)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* 停止邮件监控(内部方法)
|
|
244
|
+
*/
|
|
245
|
+
_stopEmailWatch() {
|
|
246
|
+
const { stopEmailWatch } = require('./monitor')
|
|
247
|
+
return stopEmailWatch(this)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* 获取监控状态(内部方法)
|
|
252
|
+
*/
|
|
253
|
+
_getEmailWatchStatus() {
|
|
254
|
+
const { getEmailWatchStatus } = require('./monitor')
|
|
255
|
+
return getEmailWatchStatus(this)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* 检查新邮件(内部方法)
|
|
260
|
+
*/
|
|
261
|
+
async _checkNewEmails() {
|
|
262
|
+
const { checkNewEmails } = require('./monitor')
|
|
263
|
+
return checkNewEmails(this)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
uninstall(framework) {
|
|
267
|
+
// 停止邮件监控
|
|
268
|
+
if (this._watchInterval) {
|
|
269
|
+
clearInterval(this._watchInterval)
|
|
270
|
+
this._watchInterval = null
|
|
271
|
+
}
|
|
272
|
+
this._watchEnabled = false
|
|
273
|
+
this._watchConfig = null
|
|
274
|
+
this._framework = null
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
module.exports = { EmailPlugin }
|