foliko 1.0.81 → 1.0.83

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.
Files changed (88) hide show
  1. package/cli/bin/foliko.js +12 -12
  2. package/cli/src/commands/chat.js +143 -143
  3. package/cli/src/commands/list.js +93 -93
  4. package/cli/src/index.js +75 -75
  5. package/cli/src/ui/chat-ui.js +201 -201
  6. package/cli/src/utils/ansi.js +40 -40
  7. package/cli/src/utils/markdown.js +292 -292
  8. package/examples/ambient-example.js +194 -194
  9. package/examples/basic.js +115 -115
  10. package/examples/bootstrap.js +121 -121
  11. package/examples/mcp-example.js +56 -56
  12. package/examples/skill-example.js +49 -49
  13. package/examples/test-chat.js +137 -137
  14. package/examples/test-mcp.js +85 -85
  15. package/examples/test-reload.js +59 -59
  16. package/examples/test-telegram.js +50 -50
  17. package/examples/test-tg-bot.js +45 -45
  18. package/examples/test-tg-simple.js +47 -47
  19. package/examples/test-tg.js +62 -62
  20. package/examples/test-think.js +43 -43
  21. package/examples/test-web-plugin.js +103 -103
  22. package/examples/test-weixin-feishu.js +103 -103
  23. package/examples/workflow.js +158 -158
  24. package/package.json +83 -83
  25. package/plugins/ai-plugin.js +102 -102
  26. package/plugins/ambient-agent/EventWatcher.js +113 -113
  27. package/plugins/ambient-agent/ExplorerLoop.js +640 -640
  28. package/plugins/ambient-agent/GoalManager.js +197 -197
  29. package/plugins/ambient-agent/Reflector.js +95 -95
  30. package/plugins/ambient-agent/StateStore.js +90 -90
  31. package/plugins/ambient-agent/constants.js +101 -101
  32. package/plugins/ambient-agent/index.js +579 -579
  33. package/plugins/audit-plugin.js +187 -187
  34. package/plugins/default-plugins.js +548 -548
  35. package/plugins/email/constants.js +64 -64
  36. package/plugins/email/handlers.js +461 -461
  37. package/plugins/email/index.js +278 -278
  38. package/plugins/email/monitor.js +269 -269
  39. package/plugins/email/parser.js +138 -138
  40. package/plugins/email/reply.js +151 -151
  41. package/plugins/email/utils.js +124 -124
  42. package/plugins/extension-executor-plugin.js +326 -326
  43. package/plugins/feishu-plugin.js +481 -481
  44. package/plugins/file-system-plugin.js +920 -920
  45. package/plugins/gate-trading.js +747 -747
  46. package/plugins/install-plugin.js +199 -199
  47. package/plugins/python-executor-plugin.js +367 -367
  48. package/plugins/python-plugin-loader.js +651 -651
  49. package/plugins/rules-plugin.js +294 -294
  50. package/plugins/scheduler-plugin.js +691 -691
  51. package/plugins/session-plugin.js +494 -494
  52. package/plugins/shell-executor-plugin.js +197 -197
  53. package/plugins/storage-plugin.js +263 -263
  54. package/plugins/subagent-plugin.js +845 -845
  55. package/plugins/telegram-plugin.js +482 -482
  56. package/plugins/think-plugin.js +345 -345
  57. package/plugins/tools-plugin.js +196 -196
  58. package/plugins/web-plugin.js +637 -637
  59. package/plugins/weixin-plugin.js +545 -545
  60. package/src/capabilities/index.js +11 -11
  61. package/src/capabilities/skill-manager.js +609 -609
  62. package/src/capabilities/workflow-engine.js +1109 -1109
  63. package/src/core/agent-chat.js +1 -1
  64. package/src/core/agent.js +958 -958
  65. package/src/core/framework.js +465 -465
  66. package/src/core/index.js +19 -19
  67. package/src/core/plugin-base.js +262 -262
  68. package/src/core/plugin-manager.js +863 -863
  69. package/src/core/provider.js +114 -114
  70. package/src/core/sub-agent-config.js +264 -264
  71. package/src/core/system-prompt-builder.js +120 -120
  72. package/src/core/tool-registry.js +517 -517
  73. package/src/core/tool-router.js +297 -297
  74. package/src/executors/executor-base.js +58 -58
  75. package/src/executors/mcp-executor.js +845 -845
  76. package/src/index.js +25 -25
  77. package/src/utils/circuit-breaker.js +301 -301
  78. package/src/utils/error-boundary.js +363 -363
  79. package/src/utils/error.js +374 -374
  80. package/src/utils/event-emitter.js +97 -97
  81. package/src/utils/id.js +133 -133
  82. package/src/utils/index.js +217 -217
  83. package/src/utils/logger.js +181 -181
  84. package/src/utils/plugin-helpers.js +90 -90
  85. package/src/utils/retry.js +122 -122
  86. package/src/utils/sandbox.js +292 -292
  87. package/test/tool-registry-validation.test.js +218 -218
  88. package/website/script.js +136 -136
@@ -1,138 +1,138 @@
1
- /**
2
- * Email 插件 - 邮件解析器
3
- */
4
-
5
- const { simpleParser } = require('mailparser')
6
-
7
- /**
8
- * 解析邮件内容
9
- * @param {Stream} stream - 邮件流
10
- * @returns {Promise<Object>} 解析后的邮件对象
11
- */
12
- async function parseEmail(stream) {
13
- return await simpleParser(stream)
14
- }
15
-
16
- /**
17
- * 将邮件对象标准化
18
- * @param {Object} mail - mailparser 解析结果
19
- * @param {number} defaultUid - 默认 UID
20
- * @returns {Object} 标准化的邮件对象
21
- */
22
- function normalizeEmail(mail, defaultUid) {
23
- return {
24
- uid: mail.uid || defaultUid,
25
- messageId: mail.messageId,
26
- subject: mail.subject,
27
- from: mail.from?.text || '',
28
- fromName: mail.from?.value?.[0]?.name || '',
29
- fromAddress: mail.from?.value?.[0]?.address || '',
30
- to: mail.to?.text || '',
31
- toName: mail.to?.value?.[0]?.name || '',
32
- toAddress: mail.to?.value?.[0]?.address || '',
33
- date: mail.date?.toISOString() || '',
34
- text: mail.text || mail.textAsHtml || '',
35
- html: mail.html,
36
- attachments: parseAttachments(mail.attachments),
37
- headers: parseHeaders(mail.headers)
38
- }
39
- }
40
-
41
- /**
42
- * 解析附件列表
43
- * @param {Array} attachments - 附件数组
44
- * @returns {Array} 标准化的附件列表
45
- */
46
- function parseAttachments(attachments) {
47
- if (!attachments || !Array.isArray(attachments)) {
48
- return []
49
- }
50
-
51
- return attachments.map(att => ({
52
- filename: att.filename,
53
- contentType: att.contentType,
54
- contentId: att.contentId,
55
- size: att.size,
56
- headers: att.headers
57
- }))
58
- }
59
-
60
- /**
61
- * 解析邮件头
62
- * @param {Map|Object} headers - 邮件头
63
- * @returns {Object} 标准化的头信息
64
- */
65
- function parseHeaders(headers) {
66
- if (!headers) return {}
67
-
68
- const result = {}
69
- if (headers instanceof Map) {
70
- for (const [key, value] of headers) {
71
- result[key.toLowerCase()] = Array.isArray(value) ? value.join(', ') : value
72
- }
73
- } else {
74
- for (const [key, value] of Object.entries(headers)) {
75
- result[key.toLowerCase()] = Array.isArray(value) ? value.join(', ') : value
76
- }
77
- }
78
-
79
- return result
80
- }
81
-
82
- /**
83
- * 检测邮件编码
84
- * @param {string} charset - 字符集
85
- * @returns {string} 标准化的字符集名称
86
- */
87
- function normalizeCharset(charset) {
88
- if (!charset) return 'utf-8'
89
-
90
- const charsetMap = {
91
- 'gb2312': 'gb18030',
92
- 'gbk': 'gb18030',
93
- 'windows-1252': 'cp1252'
94
- }
95
-
96
- return charsetMap[charset.toLowerCase()] || charset.toLowerCase()
97
- }
98
-
99
- /**
100
- * 清理邮件文本内容
101
- * @param {string} text - 原始文本
102
- * @returns {string} 清理后的文本
103
- */
104
- function cleanText(text) {
105
- if (!text) return ''
106
-
107
- return text
108
- .replace(/\r\n/g, '\n') // 统一换行符
109
- .replace(/\t/g, ' ') // Tab 转为空格
110
- .replace(/ +/g, ' ') // 多个空格合并为一个
111
- .replace(/\n{3,}/g, '\n\n') // 超过两个连续换行合并为两个
112
- .trim()
113
- }
114
-
115
- /**
116
- * 从文本中提取邮箱地址
117
- * @param {string} text - 文本内容
118
- * @returns {Array<string>} 邮箱地址列表
119
- */
120
- function extractEmails(text) {
121
- if (!text) return []
122
-
123
- const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g
124
- const matches = text.match(emailRegex) || []
125
-
126
- // 去重
127
- return [...new Set(matches)]
128
- }
129
-
130
- module.exports = {
131
- parseEmail,
132
- normalizeEmail,
133
- parseAttachments,
134
- parseHeaders,
135
- normalizeCharset,
136
- cleanText,
137
- extractEmails
138
- }
1
+ /**
2
+ * Email 插件 - 邮件解析器
3
+ */
4
+
5
+ const { simpleParser } = require('mailparser')
6
+
7
+ /**
8
+ * 解析邮件内容
9
+ * @param {Stream} stream - 邮件流
10
+ * @returns {Promise<Object>} 解析后的邮件对象
11
+ */
12
+ async function parseEmail(stream) {
13
+ return await simpleParser(stream)
14
+ }
15
+
16
+ /**
17
+ * 将邮件对象标准化
18
+ * @param {Object} mail - mailparser 解析结果
19
+ * @param {number} defaultUid - 默认 UID
20
+ * @returns {Object} 标准化的邮件对象
21
+ */
22
+ function normalizeEmail(mail, defaultUid) {
23
+ return {
24
+ uid: mail.uid || defaultUid,
25
+ messageId: mail.messageId,
26
+ subject: mail.subject,
27
+ from: mail.from?.text || '',
28
+ fromName: mail.from?.value?.[0]?.name || '',
29
+ fromAddress: mail.from?.value?.[0]?.address || '',
30
+ to: mail.to?.text || '',
31
+ toName: mail.to?.value?.[0]?.name || '',
32
+ toAddress: mail.to?.value?.[0]?.address || '',
33
+ date: mail.date?.toISOString() || '',
34
+ text: mail.text || mail.textAsHtml || '',
35
+ html: mail.html,
36
+ attachments: parseAttachments(mail.attachments),
37
+ headers: parseHeaders(mail.headers)
38
+ }
39
+ }
40
+
41
+ /**
42
+ * 解析附件列表
43
+ * @param {Array} attachments - 附件数组
44
+ * @returns {Array} 标准化的附件列表
45
+ */
46
+ function parseAttachments(attachments) {
47
+ if (!attachments || !Array.isArray(attachments)) {
48
+ return []
49
+ }
50
+
51
+ return attachments.map(att => ({
52
+ filename: att.filename,
53
+ contentType: att.contentType,
54
+ contentId: att.contentId,
55
+ size: att.size,
56
+ headers: att.headers
57
+ }))
58
+ }
59
+
60
+ /**
61
+ * 解析邮件头
62
+ * @param {Map|Object} headers - 邮件头
63
+ * @returns {Object} 标准化的头信息
64
+ */
65
+ function parseHeaders(headers) {
66
+ if (!headers) return {}
67
+
68
+ const result = {}
69
+ if (headers instanceof Map) {
70
+ for (const [key, value] of headers) {
71
+ result[key.toLowerCase()] = Array.isArray(value) ? value.join(', ') : value
72
+ }
73
+ } else {
74
+ for (const [key, value] of Object.entries(headers)) {
75
+ result[key.toLowerCase()] = Array.isArray(value) ? value.join(', ') : value
76
+ }
77
+ }
78
+
79
+ return result
80
+ }
81
+
82
+ /**
83
+ * 检测邮件编码
84
+ * @param {string} charset - 字符集
85
+ * @returns {string} 标准化的字符集名称
86
+ */
87
+ function normalizeCharset(charset) {
88
+ if (!charset) return 'utf-8'
89
+
90
+ const charsetMap = {
91
+ 'gb2312': 'gb18030',
92
+ 'gbk': 'gb18030',
93
+ 'windows-1252': 'cp1252'
94
+ }
95
+
96
+ return charsetMap[charset.toLowerCase()] || charset.toLowerCase()
97
+ }
98
+
99
+ /**
100
+ * 清理邮件文本内容
101
+ * @param {string} text - 原始文本
102
+ * @returns {string} 清理后的文本
103
+ */
104
+ function cleanText(text) {
105
+ if (!text) return ''
106
+
107
+ return text
108
+ .replace(/\r\n/g, '\n') // 统一换行符
109
+ .replace(/\t/g, ' ') // Tab 转为空格
110
+ .replace(/ +/g, ' ') // 多个空格合并为一个
111
+ .replace(/\n{3,}/g, '\n\n') // 超过两个连续换行合并为两个
112
+ .trim()
113
+ }
114
+
115
+ /**
116
+ * 从文本中提取邮箱地址
117
+ * @param {string} text - 文本内容
118
+ * @returns {Array<string>} 邮箱地址列表
119
+ */
120
+ function extractEmails(text) {
121
+ if (!text) return []
122
+
123
+ const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g
124
+ const matches = text.match(emailRegex) || []
125
+
126
+ // 去重
127
+ return [...new Set(matches)]
128
+ }
129
+
130
+ module.exports = {
131
+ parseEmail,
132
+ normalizeEmail,
133
+ parseAttachments,
134
+ parseHeaders,
135
+ normalizeCharset,
136
+ cleanText,
137
+ extractEmails
138
+ }
@@ -1,151 +1,151 @@
1
- /**
2
- * Email 插件 - 自动回复
3
- */
4
-
5
- const { EMAIL_DEFAULTS } = require('./constants')
6
-
7
- /**
8
- * 处理自动回复
9
- * @param {Object} emailPlugin - EmailPlugin 实例
10
- * @param {Object} args - 回复参数
11
- * @returns {Promise<Object>} 回复结果
12
- */
13
- async function handleAutoReply(emailPlugin, args) {
14
- let { to, subject, body, from, _event, prompt, messageId, inReplyTo } = args
15
-
16
- // 如果没有直接参数,尝试从 _event 提取
17
- // 支持多种事件结构:{ email, timestamp } 或 { data: { email } } 或 { data: { ... } }
18
- if (!to && !subject && !body && _event) {
19
- // 兼容多种事件结构
20
- const email = _event.email || _event.data?.email || _event.data || {}
21
- from = email.from?.text || email.from || ''
22
- to = email.to?.text || email.to || ''
23
- subject = email.subject || ''
24
- body = email.text || email.body || ''
25
- // 优先使用 _event 中的 uid/messageId
26
- if (!messageId) {
27
- messageId = email.messageId || email.uid || _event.data?.messageId || _event.data?.uid
28
- }
29
- }
30
-
31
- // 如果 _event 没有有效数据,不允许自动读取所有邮件
32
- if (!_event || (!_event.email && !_event.data)) {
33
- return {
34
- success: false,
35
- error: '缺少邮件数据:_event 中没有有效的邮件信息,无法自动回复。请确认是否在收到新邮件事件时调用此工具。'
36
- }
37
- }
38
-
39
- // 优先使用传入的 inReplyTo,否则用 messageId
40
- const replyTo = inReplyTo || messageId
41
-
42
- // 检查必要参数
43
- if (!from && !to) {
44
- return { success: false, error: '缺少收件人地址' }
45
- }
46
- if (!body) {
47
- return { success: false, error: '缺少邮件内容' }
48
- }
49
-
50
- try {
51
- // 使用子 Agent 生成回复
52
- const replyAgent = emailPlugin._framework.createSubAgent({
53
- name: 'email_replier',
54
- role: '邮件自动回复助手,专注于生成专业、礼貌、简洁的邮件回复',
55
- parentTools: []
56
- })
57
-
58
- // 构建提示让 LLM 生成回复
59
- const finalPrompt = prompt || `你是一封邮件自动回复助手。请根据以下邮件内容,生成一封专业的回复邮件。
60
-
61
- 【原始邮件】
62
- 发件人: ${from || to}
63
- 主题: ${subject}
64
- 内容:
65
- ${body}
66
-
67
- 【要求】
68
- 1. 回复内容要针对邮件中的问题或内容进行回复
69
- 2. 语言要专业、礼貌、简洁
70
- 3. 只输出邮件正文内容,不要额外解释
71
- 4. 回复语言应与原邮件一致(如果原邮件是中文,则用中文回复)`
72
-
73
- // 等待 Agent 生成回复(带超时保护)
74
- const timeoutMs = args.timeout || EMAIL_DEFAULTS.timeout
75
- const timeoutPromise = new Promise((_, reject) => {
76
- setTimeout(() => reject(new Error(`AI回复生成超时(${timeoutMs / 1000}秒)`)), timeoutMs)
77
- })
78
-
79
- const replyPromise = replyAgent.chat(finalPrompt, { maxSteps: 3 })
80
- const replyResult = await Promise.race([replyPromise, timeoutPromise])
81
-
82
- // 提取回复内容
83
- let replyContent = ''
84
- if (typeof replyResult === 'string') {
85
- replyContent = replyResult.trim()
86
- } else if (replyResult && replyResult.content) {
87
- replyContent = replyResult.content.trim()
88
- } else if (replyResult && replyResult.message) {
89
- replyContent = replyResult.message.trim()
90
- } else {
91
- replyContent = JSON.stringify(replyResult).trim()
92
- }
93
-
94
- // 去掉思考过程标签
95
- replyContent = replyContent.replace(/<think>[\s\S]*?<\/think>/g, '').trim()
96
-
97
- if (!replyContent || replyContent.length < 5) {
98
- return { success: false, error: 'AI未能生成有效的回复内容' }
99
- }
100
-
101
- // 发送回复邮件
102
- const { sendEmail } = require('./handlers')
103
- const sendResult = await sendEmail(emailPlugin, {
104
- to: from || to,
105
- subject: `Re: ${subject}`,
106
- body: replyContent,
107
- inReplyTo: replyTo,
108
- references: replyTo ? [replyTo] : undefined
109
- })
110
-
111
- if (sendResult.success) {
112
- // 发送成功后,标记为已处理
113
- const emailData = _event?.email || _event?.data?.email || _event?.data || {}
114
- const msgId = messageId || emailData.messageId || emailData.uid
115
- if (msgId) {
116
- emailPlugin._processedEmails.add(msgId)
117
- emailPlugin._log.info(`邮件已处理: ${msgId}`)
118
-
119
- // 24小时后从已处理列表中移除
120
- setTimeout(() => {
121
- emailPlugin._processedEmails.delete(msgId)
122
- }, EMAIL_DEFAULTS.processedEmailTTL)
123
- }
124
-
125
- // 自动标记原邮件为已读
126
- const uid = emailData.uid || msgId
127
- if (uid) {
128
- try {
129
- const { markAsRead } = require('./handlers')
130
- await markAsRead(emailPlugin, { uid: uid }) // 使用 uid 而非 messageId
131
- } catch (err) {
132
- emailPlugin._log.warn(`自动标记已读失败: ${err.message}`)
133
- }
134
- }
135
-
136
- return {
137
- success: true,
138
- message: `自动回复已发送至 ${from || to}`,
139
- replyContent
140
- }
141
- } else {
142
- return { success: false, error: sendResult.error || '发送失败' }
143
- }
144
- } catch (err) {
145
- return { success: false, error: err.message }
146
- }
147
- }
148
-
149
- module.exports = {
150
- handleAutoReply
151
- }
1
+ /**
2
+ * Email 插件 - 自动回复
3
+ */
4
+
5
+ const { EMAIL_DEFAULTS } = require('./constants')
6
+
7
+ /**
8
+ * 处理自动回复
9
+ * @param {Object} emailPlugin - EmailPlugin 实例
10
+ * @param {Object} args - 回复参数
11
+ * @returns {Promise<Object>} 回复结果
12
+ */
13
+ async function handleAutoReply(emailPlugin, args) {
14
+ let { to, subject, body, from, _event, prompt, messageId, inReplyTo } = args
15
+
16
+ // 如果没有直接参数,尝试从 _event 提取
17
+ // 支持多种事件结构:{ email, timestamp } 或 { data: { email } } 或 { data: { ... } }
18
+ if (!to && !subject && !body && _event) {
19
+ // 兼容多种事件结构
20
+ const email = _event.email || _event.data?.email || _event.data || {}
21
+ from = email.from?.text || email.from || ''
22
+ to = email.to?.text || email.to || ''
23
+ subject = email.subject || ''
24
+ body = email.text || email.body || ''
25
+ // 优先使用 _event 中的 uid/messageId
26
+ if (!messageId) {
27
+ messageId = email.messageId || email.uid || _event.data?.messageId || _event.data?.uid
28
+ }
29
+ }
30
+
31
+ // 如果 _event 没有有效数据,不允许自动读取所有邮件
32
+ if (!_event || (!_event.email && !_event.data)) {
33
+ return {
34
+ success: false,
35
+ error: '缺少邮件数据:_event 中没有有效的邮件信息,无法自动回复。请确认是否在收到新邮件事件时调用此工具。'
36
+ }
37
+ }
38
+
39
+ // 优先使用传入的 inReplyTo,否则用 messageId
40
+ const replyTo = inReplyTo || messageId
41
+
42
+ // 检查必要参数
43
+ if (!from && !to) {
44
+ return { success: false, error: '缺少收件人地址' }
45
+ }
46
+ if (!body) {
47
+ return { success: false, error: '缺少邮件内容' }
48
+ }
49
+
50
+ try {
51
+ // 使用子 Agent 生成回复
52
+ const replyAgent = emailPlugin._framework.createSubAgent({
53
+ name: 'email_replier',
54
+ role: '邮件自动回复助手,专注于生成专业、礼貌、简洁的邮件回复',
55
+ parentTools: []
56
+ })
57
+
58
+ // 构建提示让 LLM 生成回复
59
+ const finalPrompt = prompt || `你是一封邮件自动回复助手。请根据以下邮件内容,生成一封专业的回复邮件。
60
+
61
+ 【原始邮件】
62
+ 发件人: ${from || to}
63
+ 主题: ${subject}
64
+ 内容:
65
+ ${body}
66
+
67
+ 【要求】
68
+ 1. 回复内容要针对邮件中的问题或内容进行回复
69
+ 2. 语言要专业、礼貌、简洁
70
+ 3. 只输出邮件正文内容,不要额外解释
71
+ 4. 回复语言应与原邮件一致(如果原邮件是中文,则用中文回复)`
72
+
73
+ // 等待 Agent 生成回复(带超时保护)
74
+ const timeoutMs = args.timeout || EMAIL_DEFAULTS.timeout
75
+ const timeoutPromise = new Promise((_, reject) => {
76
+ setTimeout(() => reject(new Error(`AI回复生成超时(${timeoutMs / 1000}秒)`)), timeoutMs)
77
+ })
78
+
79
+ const replyPromise = replyAgent.chat(finalPrompt, { maxSteps: 3 })
80
+ const replyResult = await Promise.race([replyPromise, timeoutPromise])
81
+
82
+ // 提取回复内容
83
+ let replyContent = ''
84
+ if (typeof replyResult === 'string') {
85
+ replyContent = replyResult.trim()
86
+ } else if (replyResult && replyResult.content) {
87
+ replyContent = replyResult.content.trim()
88
+ } else if (replyResult && replyResult.message) {
89
+ replyContent = replyResult.message.trim()
90
+ } else {
91
+ replyContent = JSON.stringify(replyResult).trim()
92
+ }
93
+
94
+ // 去掉思考过程标签
95
+ replyContent = replyContent.replace(/<think>[\s\S]*?<\/think>/g, '').trim()
96
+
97
+ if (!replyContent || replyContent.length < 5) {
98
+ return { success: false, error: 'AI未能生成有效的回复内容' }
99
+ }
100
+
101
+ // 发送回复邮件
102
+ const { sendEmail } = require('./handlers')
103
+ const sendResult = await sendEmail(emailPlugin, {
104
+ to: from || to,
105
+ subject: `Re: ${subject}`,
106
+ body: replyContent,
107
+ inReplyTo: replyTo,
108
+ references: replyTo ? [replyTo] : undefined
109
+ })
110
+
111
+ if (sendResult.success) {
112
+ // 发送成功后,标记为已处理
113
+ const emailData = _event?.email || _event?.data?.email || _event?.data || {}
114
+ const msgId = messageId || emailData.messageId || emailData.uid
115
+ if (msgId) {
116
+ emailPlugin._processedEmails.add(msgId)
117
+ emailPlugin._log.info(`邮件已处理: ${msgId}`)
118
+
119
+ // 24小时后从已处理列表中移除
120
+ setTimeout(() => {
121
+ emailPlugin._processedEmails.delete(msgId)
122
+ }, EMAIL_DEFAULTS.processedEmailTTL)
123
+ }
124
+
125
+ // 自动标记原邮件为已读
126
+ const uid = emailData.uid || msgId
127
+ if (uid) {
128
+ try {
129
+ const { markAsRead } = require('./handlers')
130
+ await markAsRead(emailPlugin, { uid: uid }) // 使用 uid 而非 messageId
131
+ } catch (err) {
132
+ emailPlugin._log.warn(`自动标记已读失败: ${err.message}`)
133
+ }
134
+ }
135
+
136
+ return {
137
+ success: true,
138
+ message: `自动回复已发送至 ${from || to}`,
139
+ replyContent
140
+ }
141
+ } else {
142
+ return { success: false, error: sendResult.error || '发送失败' }
143
+ }
144
+ } catch (err) {
145
+ return { success: false, error: err.message }
146
+ }
147
+ }
148
+
149
+ module.exports = {
150
+ handleAutoReply
151
+ }