foliko 1.0.40 → 1.0.41

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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Telegram 插件 v2
2
+ * Telegram 插件
3
3
  * 支持绑定主Agent进行持续对话
4
4
  *
5
5
  * 配置:
@@ -15,615 +15,400 @@ const { z } = require('zod')
15
15
  // 转义 MarkdownV2 特殊字符
16
16
  function escapeMarkdown(text) {
17
17
  if (!text) return ''
18
- // MarkdownV2 需要转义的所有字符
19
18
  return text.replace(/([\_*\[\]()~`>#+\-=|{}.!])/g, '\\$1')
20
19
  }
21
20
 
22
- module.exports = function(Plugin) {
23
- return class TelegramPlugin extends Plugin {
24
- constructor(config = {}) {
25
- super()
26
- this.name = 'telegram'
27
- this.version = '2.0.0'
28
- this.description = 'Telegram 对话插件,绑定主Agent进行持续对话'
29
- this.priority = 80
30
- // 默认不启用,需要在 plugins.json 中设置 enabled: true
31
- this.enabled = false
32
- this.systemPrompt='你是一个有帮助的AI助手。回复内容不要使用markdown格式文本。'
33
-
34
- this.config = {
35
- botToken: config.botToken || process.env.TELEGRAM_BOT_TOKEN,
36
- allowedChats: config.allowedChats || [],
37
- groupMode: config.groupMode || false,
38
- prefix: config.prefix || '/'
39
- }
40
-
41
- this._framework = null
42
- this._bot = null
43
- this._sessionPlugin = null
44
- this._sessionDeleteHandler = null
45
- this._sessionAgents = new Map() // chatId -> Agent
21
+ class TelegramPlugin extends Plugin {
22
+ constructor(config = {}) {
23
+ super()
24
+ this.name = 'telegram'
25
+ this.version = '2.1.0'
26
+ this.description = 'Telegram 对话插件,绑定主Agent进行持续对话'
27
+ this.priority = 80
28
+ this.enabled = false
29
+ this.systemPrompt = '你是一个有帮助的AI助手。回复内容不要使用markdown格式文本。'
30
+
31
+ this.config = {
32
+ botToken: config.botToken || process.env.TELEGRAM_BOT_TOKEN,
33
+ allowedChats: config.allowedChats || [],
34
+ groupMode: config.groupMode || false,
35
+ prefix: config.prefix || '/'
46
36
  }
47
37
 
48
- install(framework) {
49
- this._framework = framework
38
+ this._framework = null
39
+ this._bot = null
40
+ this._sessionPlugin = null
41
+ this._sessionDeleteHandler = null
42
+ this._sessionAgents = new Map()
43
+ }
44
+
45
+ install(framework) {
46
+ this._framework = framework
47
+ return this
48
+ }
49
+
50
+ start(framework) {
51
+ if (!this.config.botToken) {
52
+ console.warn('[Telegram] No bot token. Set TELEGRAM_BOT_TOKEN env var.')
50
53
  return this
51
54
  }
52
55
 
53
- start(framework) {
54
- if (!this.config.botToken) {
55
- console.warn('[Telegram] No bot token. Set TELEGRAM_BOT_TOKEN env var.')
56
- return this
57
- }
58
-
59
- // 获取 SessionPlugin 引用
60
- this._sessionPlugin = framework.pluginManager.get('session')
56
+ this._framework = framework
57
+ this._sessionPlugin = framework.pluginManager.get('session')
61
58
 
62
- // 监听 SessionPlugin 的会话删除事件
63
- if (this._sessionPlugin) {
64
- this._sessionDeleteHandler = (sessionId) => {
65
- // 只处理 telegram 会话的删除
66
- if (sessionId.startsWith('telegram_')) {
67
- console.log(`[Telegram] Session deleted: ${sessionId}`)
68
- }
59
+ if (this._sessionPlugin) {
60
+ this._sessionDeleteHandler = (sessionId) => {
61
+ if (sessionId.startsWith('telegram_')) {
62
+ console.log(`[Telegram] Session deleted: ${sessionId}`)
69
63
  }
70
- this._sessionPlugin.on('session:deleted', this._sessionDeleteHandler)
71
64
  }
72
-
73
- this._initBot()
74
- return this
65
+ this._sessionPlugin.on('session:deleted', this._sessionDeleteHandler)
75
66
  }
76
67
 
77
- _initBot() {
78
- try {
79
- // 添加 .agent/node_modules 到搜索路径
80
- // const path = require('path')
81
- // const agentNodeModules = path.join(process.cwd(), '.agent', 'node_modules')
82
- // if (!module.paths.includes(agentNodeModules)) {
83
- // module.paths.unshift(agentNodeModules)
84
- // }
85
-
86
- const TelegramBot = require('node-telegram-bot-api')
87
- this._bot = new TelegramBot(this.config.botToken, { polling: true })
88
-
89
- console.log('[Telegram] Bot started successfully')
90
-
91
- // 注册菜单命令
92
- this._bot.setMyCommands([
93
- { command: 'start', description: '显示帮助信息' },
94
- { command: 'clear', description: '清除对话历史' },
95
- { command: 'history', description: '查看对话状态' }
96
- ]).then(() => {
97
- console.log('[Telegram] Commands registered')
98
- }).catch((err) => {
99
- console.error('[Telegram] Failed to register commands:', err.message)
100
- })
68
+ this._initBot()
69
+ return this
70
+ }
101
71
 
102
- // 监听消息
103
- this._bot.on('message', (msg) => this._handleMessage(msg))
72
+ _initBot() {
73
+ try {
74
+ const TelegramBot = require('node-telegram-bot-api')
75
+ this._bot = new TelegramBot(this.config.botToken, { polling: true })
104
76
 
105
- // 监听编辑消息
106
- this._bot.on('edit_message', (msg) => this._handleEdit(msg))
77
+ console.log('[Telegram] Bot started successfully')
107
78
 
108
- // 监听回调
109
- this._bot.on('callback_query', (query) => this._handleCallback(query))
79
+ this._bot.setMyCommands([
80
+ { command: 'start', description: '显示帮助信息' },
81
+ { command: 'clear', description: '清除对话历史' },
82
+ { command: 'history', description: '查看对话状态' }
83
+ ]).catch((err) => {
84
+ console.error('[Telegram] Failed to register commands:', err.message)
85
+ })
110
86
 
111
- // 监听错误
112
- this._bot.on('polling_error', (err) => {
113
- console.error('[Telegram] Polling error:', err.message)
114
- })
87
+ this._bot.on('message', (msg) => this._handleMessage(msg))
88
+ this._bot.on('edit_message', (msg) => this._handleEdit(msg))
89
+ this._bot.on('callback_query', (query) => this._handleCallback(query))
90
+ this._bot.on('polling_error', (err) => console.error('[Telegram] Polling error:', err.message))
91
+ this._bot.on('error', (err) => console.error('[Telegram] Bot error:', err.message))
115
92
 
116
- this._bot.on('error', (err) => {
117
- console.error('[Telegram] Bot error:', err.message)
93
+ if (this._framework) {
94
+ this._framework.on('agent:created', (agent) => {
95
+ console.log('[Telegram] New agent created:', agent.name)
96
+ })
97
+ this._framework.on('scheduler:reminder', async (data) => {
98
+ await this._handleScheduledReminder(data)
118
99
  })
100
+ }
101
+ } catch (err) {
102
+ console.error('[Telegram] Failed to initialize bot:', err.message)
103
+ }
104
+ }
119
105
 
120
- // 监听 Agent 创建事件,确保在 Agent 创建后能正确获取
121
- if (this._framework) {
122
- this._framework.on('agent:created', (agent) => {
123
- console.log('[Telegram] New agent created:', agent.name)
124
- })
125
-
126
- // 监听定时提醒事件
127
- this._framework.on('scheduler:reminder', async (data) => {
128
- console.log('[Telegram] Received scheduler reminder:', data)
129
- await this._handleScheduledReminder(data)
130
- })
131
- }
106
+ async _handleScheduledReminder(data) {
107
+ const { taskName, message, sessionId } = data
108
+ const reminderText = `🔔 [${taskName}]\n\n${message}`
132
109
 
110
+ if (sessionId && sessionId.startsWith('telegram_')) {
111
+ const chatId = sessionId.replace('telegram_', '')
112
+ try {
113
+ await this._bot.sendMessage(chatId, reminderText)
114
+ console.log(`[Telegram] Reminder sent to chat ${chatId}`)
133
115
  } catch (err) {
134
- console.error('[Telegram] Failed to initialize bot:', err.message)
116
+ console.error(`[Telegram] Failed to send reminder:`, err.message)
135
117
  }
118
+ return
136
119
  }
137
120
 
138
- /**
139
- * 处理定时提醒
140
- */
141
- async _handleScheduledReminder(data) {
142
- const { taskName, message, sessionId } = data
143
-
144
- // 构建提醒消息
145
- const reminderText = `🔔 [${taskName}]\n\n${message}`
121
+ if (this._sessionPlugin) {
122
+ const sessions = this._sessionPlugin.listSessions()
123
+ .filter(s => s.id.startsWith('telegram_'))
124
+ .sort((a, b) => new Date(b.lastActive).getTime() - new Date(a.lastActive).getTime())
146
125
 
147
- // 如果有 sessionId telegram 类型的,发送到对应 chat
148
- if (sessionId && sessionId.startsWith('telegram_')) {
149
- const chatId = sessionId.replace('telegram_', '')
126
+ if (sessions.length > 0) {
127
+ const chatId = sessions[0].id.replace('telegram_', '')
150
128
  try {
151
129
  await this._bot.sendMessage(chatId, reminderText)
152
- console.log(`[Telegram] Reminder sent to chat ${chatId}`)
130
+ console.log(`[Telegram] Reminder sent to recent chat ${chatId}`)
153
131
  } catch (err) {
154
132
  console.error(`[Telegram] Failed to send reminder:`, err.message)
155
133
  }
156
- return
157
- }
158
-
159
- // 其他情况(包括 null 或其他 sessionId),发送到最近的 Telegram 会话
160
- if (this._sessionPlugin) {
161
- const allSessions = this._sessionPlugin.listSessions()
162
- const telegramSessions = allSessions
163
- .filter(s => s.id.startsWith('telegram_'))
164
- .sort((a, b) => new Date(b.lastActive).getTime() - new Date(a.lastActive).getTime())
165
-
166
- if (telegramSessions.length > 0) {
167
- const chatId = telegramSessions[0].id.replace('telegram_', '')
168
- try {
169
- await this._bot.sendMessage(chatId, reminderText)
170
- console.log(`[Telegram] Reminder sent to chat ${chatId}`)
171
- } catch (err) {
172
- console.error(`[Telegram] Failed to send reminder to ${chatId}:`, err.message)
173
- }
174
- } else {
175
- console.log('[Telegram] No active Telegram sessions to send reminder')
176
- }
177
- } else {
178
- console.log('[Telegram] No active Telegram sessions to send reminder')
179
134
  }
180
135
  }
136
+ }
181
137
 
182
- /**
183
- * 获取主Agent
184
- */
185
- _getMainAgent() {
186
- console.log('[Telegram] _getMainAgent called')
187
- console.log('[Telegram] _framework:', !!this._framework)
188
- console.log('[Telegram] _framework._mainAgent:', !!this._framework?._mainAgent)
189
- console.log('[Telegram] _framework._agents:', this._framework?._agents?.length || 0)
190
-
191
- if (this._framework._mainAgent) {
192
- console.log('[Telegram] returning _mainAgent')
193
- return this._framework._mainAgent
194
- }
195
- const agents = this._framework._agents || []
196
- console.log('[Telegram] returning last agent:', agents.length > 0 ? agents[agents.length - 1].name : 'none')
197
- return agents.length > 0 ? agents[agents.length - 1] : null
138
+ _getMainAgent() {
139
+ if (this._framework._mainAgent) return this._framework._mainAgent
140
+ const agents = this._framework._agents || []
141
+ return agents.length > 0 ? agents[agents.length - 1] : null
142
+ }
143
+
144
+ _getSessionAgent(chatId) {
145
+ if (this._sessionAgents.has(chatId)) {
146
+ return { agent: this._sessionAgents.get(chatId), sessionId: `telegram_${chatId}` }
198
147
  }
199
148
 
200
- /**
201
- * 获取或创建会话Agent
202
- * 使用 SessionPlugin 统一管理会话历史
203
- */
204
- _getSessionAgent(chatId) {
205
- console.log('[Telegram] _getSessionAgent called for chatId:', chatId)
206
-
207
- // 检查缓存
208
- if (this._sessionAgents.has(chatId)) {
209
- const agent = this._sessionAgents.get(chatId)
210
- const sessionId = `telegram_${chatId}`
211
- console.log('[Telegram] Reusing cached session agent for chatId:', chatId)
212
- return { agent, sessionId }
213
- }
149
+ const agent = this._framework.createSessionAgent(`telegram_${chatId}`, {
150
+ systemPrompt: this.systemPrompt
151
+ })
152
+ this._sessionAgents.set(chatId, agent)
214
153
 
215
- // 创建新 agent
216
- const agent = this._framework.createSessionAgent(`telegram_${chatId}`, {
217
- systemPrompt: this.systemPrompt
154
+ if (this._sessionPlugin) {
155
+ this._sessionPlugin.getOrCreateSession(`telegram_${chatId}`, {
156
+ metadata: { platform: 'telegram', chatId }
218
157
  })
219
- this._sessionAgents.set(chatId, agent)
220
- console.log('[Telegram] Created new session agent for chatId:', chatId)
221
-
222
- // 使用 SessionPlugin 管理会话历史
223
- if (this._sessionPlugin) {
224
- const sessionId = `telegram_${chatId}`
225
- this._sessionPlugin.getOrCreateSession(sessionId, {
226
- metadata: { platform: 'telegram', chatId }
227
- })
228
- }
229
-
230
- console.log(`[Telegram] Session ready for chatId: ${chatId}`)
231
- return { agent, sessionId: `telegram_${chatId}` }
232
158
  }
233
159
 
234
- /**
235
- * 处理消息
236
- */
237
- async _handleMessage(msg) {
238
- if (!msg || !msg.chat) return
239
-
240
- const chatId = msg.chat.id.toString()
241
-
242
- // 处理图片消息
243
- if (msg.photo) {
244
- await this._handlePhoto(msg)
245
- return
246
- }
247
-
248
- // 处理文档消息
249
- if (msg.document) {
250
- await this._handleDocument(msg)
251
- return
252
- }
253
-
254
- if (!msg.text) return
160
+ return { agent, sessionId: `telegram_${chatId}` }
161
+ }
255
162
 
256
- const text = msg.text.trim()
163
+ async _handleMessage(msg) {
164
+ if (!msg || !msg.chat) return
165
+ const chatId = msg.chat.id.toString()
257
166
 
258
- // 命令处理
259
- if (text.startsWith(this.config.prefix)) {
260
- await this._handleCommand(msg)
261
- return
262
- }
167
+ if (msg.photo) { await this._handlePhoto(msg); return }
168
+ if (msg.document) { await this._handleDocument(msg); return }
169
+ if (!msg.text) return
263
170
 
264
- // 群组模式检查
265
- if (msg.chat.type === 'group' || msg.chat.type === 'supergroup') {
266
- if (!this.config.groupMode) return
267
- }
171
+ const text = msg.text.trim()
172
+ if (text.startsWith(this.config.prefix)) {
173
+ await this._handleCommand(msg)
174
+ return
175
+ }
268
176
 
269
- // 权限检查
270
- if (!this._checkPermission(chatId)) {
271
- await this._sendMessage(chatId, '抱歉,您没有权限使用此 Bot。', msg.message_id)
272
- return
273
- }
177
+ if (msg.chat.type === 'group' || msg.chat.type === 'supergroup') {
178
+ if (!this.config.groupMode) return
179
+ }
274
180
 
275
- // 处理对话
276
- await this._processChat(chatId, text, msg.message_id)
181
+ if (!this._checkPermission(chatId)) {
182
+ await this._sendMessage(chatId, '抱歉,您没有权限使用此 Bot。', msg.message_id)
183
+ return
277
184
  }
278
185
 
279
- /**
280
- * 处理命令
281
- */
282
- async _handleCommand(msg) {
283
- const chatId = msg.chat.id.toString()
284
- const text = msg.text.trim()
285
- const parts = text.split(' ')
286
- const command = parts[0].substring(1)
287
- const args = parts.slice(1).join(' ')
288
-
289
- switch (command.toLowerCase()) {
290
- case 'start':
186
+ await this._processChat(chatId, text, msg.message_id)
187
+ }
188
+
189
+ async _handleCommand(msg) {
190
+ const chatId = msg.chat.id.toString()
191
+ const text = msg.text.trim()
192
+ const parts = text.split(' ')
193
+ const command = parts[0].substring(1)
194
+ const args = parts.slice(1).join(' ')
195
+
196
+ switch (command.toLowerCase()) {
197
+ case 'start':
198
+ await this._sendMessage(chatId,
199
+ '👋 欢迎使用 AI 助手!\n\n直接发送消息即可与我对话。\n\n可用命令:\n/start - 显示帮助\n/clear - 清除对话历史\n/history - 查看历史消息数',
200
+ msg.message_id)
201
+ break
202
+ case 'clear':
203
+ this._clearSession(chatId)
204
+ await this._sendMessage(chatId, '✅ 对话历史已清除', msg.message_id)
205
+ break
206
+ case 'history':
207
+ if (this._sessionPlugin) {
208
+ const session = this._sessionPlugin.getSession(`telegram_${chatId}`)
209
+ const sessions = this._sessionPlugin.listSessions().filter(s => s.id.startsWith('telegram_'))
291
210
  await this._sendMessage(chatId,
292
- '👋 欢迎使用 AI 助手!\n\n' +
293
- '直接发送消息即可与我对话,我会尽力帮助您。\n\n' +
294
- '可用命令:\n' +
295
- '/start - 显示帮助\n' +
296
- '/clear - 清除对话历史\n' +
297
- '/history - 查看历史消息数',
211
+ `📊 当前状态\n\n会话数:${sessions.length}\n历史消息:${session?.messages?.length || 0}\n最后活跃:${session?.lastActive?.toLocaleString() || '无'}`,
298
212
  msg.message_id)
299
- break
300
-
301
- case 'clear':
302
- this._clearSession(chatId)
303
- await this._sendMessage(chatId, '✅ 对话历史已清除', msg.message_id)
304
- break
305
-
306
- case 'history':
307
- if (this._sessionPlugin) {
308
- const sessionId = `telegram_${chatId}`
309
- const session = this._sessionPlugin.getSession(sessionId)
310
- const allSessions = this._sessionPlugin.listSessions()
311
- const telegramSessionCount = allSessions.filter(s => s.id.startsWith('telegram_')).length
312
- await this._sendMessage(chatId,
313
- `📊 当前状态\n\n会话数:${telegramSessionCount}\n` +
314
- `历史消息:${session?.messages.length || 0}\n` +
315
- `最后活跃:${session?.lastActive?.toLocaleString() || '无'}`,
316
- msg.message_id)
317
- } else {
318
- await this._sendMessage(chatId, '❌ 会话服务不可用', msg.message_id)
319
- }
320
- break
321
-
322
- default:
323
- // 未识别命令,作为普通消息处理
324
- await this._processChat(chatId, text, msg.message_id)
325
- }
213
+ } else {
214
+ await this._sendMessage(chatId, '❌ 会话服务不可用', msg.message_id)
215
+ }
216
+ break
217
+ default:
218
+ await this._processChat(chatId, text, msg.message_id)
326
219
  }
220
+ }
327
221
 
328
- /**
329
- * 处理对话
330
- */
331
- async _processChat(chatId, text, replyToMessageId) {
332
- console.log('[Telegram] _processChat called, chatId:', chatId, 'text:', text.substring(0, 50))
333
- const sessionInfo = this._getSessionAgent(chatId)
334
- console.log('[Telegram] session:', !!sessionInfo)
335
- if (!sessionInfo) {
336
- await this._sendMessage(chatId, '❌ AI 服务未初始化', replyToMessageId)
337
- return
338
- }
222
+ async _processChat(chatId, text, replyToMessageId) {
223
+ const sessionInfo = this._getSessionAgent(chatId)
224
+ if (!sessionInfo) {
225
+ await this._sendMessage(chatId, '❌ AI 服务未初始化', replyToMessageId)
226
+ return
227
+ }
339
228
 
340
- const { agent, sessionId } = sessionInfo
229
+ const { agent, sessionId } = sessionInfo
341
230
 
342
- // 使用 SessionPlugin 添加用户消息到历史
343
- if (this._sessionPlugin) {
344
- this._sessionPlugin.addMessage(sessionId, { role: 'user', content: text })
345
- }
231
+ if (this._sessionPlugin) {
232
+ this._sessionPlugin.addMessage(sessionId, { role: 'user', content: text })
233
+ }
346
234
 
347
- // 发送思考中消息
348
- let thinkingMsg
349
- try {
350
- thinkingMsg = await this._bot.sendMessage(chatId, '🤔 思考中...', {
351
- reply_to_message_id: replyToMessageId
352
- })
353
- } catch (err) {
354
- console.error('[Telegram] Send thinking error:', err.message)
355
- return
356
- }
235
+ let thinkingMsg
236
+ try {
237
+ thinkingMsg = await this._bot.sendMessage(chatId, '🤔 思考中...', {
238
+ reply_to_message_id: replyToMessageId
239
+ })
240
+ } catch (err) {
241
+ console.error('[Telegram] Send thinking error:', err.message)
242
+ return
243
+ }
357
244
 
358
- try {
359
- let fullResponse = ''
360
-
361
- // 使用流式响应
362
- for await (const chunk of agent.chatStream(text, {
363
- sessionId: sessionId
364
- })) {
365
- // chatStream 返回 { type: 'text', text } { type: 'tool-call', toolName, args }
366
- if (chunk.type === 'text' && chunk.text) {
367
- fullResponse += chunk.text
368
-
369
- // 定期更新消息
370
- if (fullResponse.length % 100 === 0) {
371
- try {
372
- await this._bot.editMessageText(`📝 ${escapeMarkdown(fullResponse)}▌`, {
373
- chat_id: chatId,
374
- message_id: thinkingMsg.message_id
375
- })
376
- } catch (e) {
377
- // 忽略编辑错误
378
- }
379
- }
245
+ try {
246
+ let fullResponse = ''
247
+ for await (const chunk of agent.chatStream(text, { sessionId })) {
248
+ if (chunk.type === 'text' && chunk.text) {
249
+ fullResponse += chunk.text
250
+ if (fullResponse.length % 100 === 0) {
251
+ try {
252
+ await this._bot.editMessageText(`📝 ${escapeMarkdown(fullResponse)}▌`, {
253
+ chat_id: chatId,
254
+ message_id: thinkingMsg.message_id
255
+ })
256
+ } catch (e) { /* ignore */ }
380
257
  }
381
258
  }
382
-
383
- // 保存助手回复到历史(使用 SessionPlugin)
384
- if (this._sessionPlugin) {
385
- this._sessionPlugin.addMessage(sessionId, { role: 'assistant', content: fullResponse })
386
- }
387
-
388
- // 发送最终回复(转义 Markdown 特殊字符)
389
- const safeResponse = escapeMarkdown(fullResponse) || '抱歉,我没有收到有效的回复。'
390
- await this._bot.editMessageText(safeResponse, {
391
- chat_id: chatId,
392
- message_id: thinkingMsg.message_id,
393
- parse_mode: 'MarkdownV2'
394
- })
395
-
396
- } catch (err) {
397
- console.error('[Telegram] Chat error:', err)
398
- await this._bot.editMessageText(escapeMarkdown(`❌ 发生错误:${err.message}`), {
399
- chat_id: chatId,
400
- message_id: thinkingMsg.message_id
401
- })
402
259
  }
403
- }
404
260
 
405
- /**
406
- * 处理编辑消息
407
- */
408
- async _handleEdit(msg) {
409
- // 支持编辑后重新处理
410
- }
261
+ if (this._sessionPlugin) {
262
+ this._sessionPlugin.addMessage(sessionId, { role: 'assistant', content: fullResponse })
263
+ }
411
264
 
412
- /**
413
- * 处理回调查询
414
- */
415
- async _handleCallback(query) {
416
- await this._bot.answerCallbackQuery(query.id, {
417
- text: '处理中...'
265
+ const safeResponse = escapeMarkdown(fullResponse) || '抱歉,我没有收到有效的回复。'
266
+ await this._bot.editMessageText(safeResponse, {
267
+ chat_id: chatId,
268
+ message_id: thinkingMsg.message_id,
269
+ parse_mode: 'MarkdownV2'
270
+ })
271
+ } catch (err) {
272
+ console.error('[Telegram] Chat error:', err)
273
+ await this._bot.editMessageText(escapeMarkdown(`❌ 发生错误:${err.message}`), {
274
+ chat_id: chatId,
275
+ message_id: thinkingMsg.message_id
418
276
  })
419
277
  }
278
+ }
420
279
 
421
- /**
422
- * 权限检查
423
- */
424
- _checkPermission(chatId) {
425
- if (this.config.allowedChats.length === 0) return true
426
- return this.config.allowedChats.includes(chatId)
427
- }
280
+ async _handleEdit(msg) { /* 支持编辑后重新处理 */ }
428
281
 
429
- /**
430
- * 处理图片消息
431
- */
432
- async _handlePhoto(msg) {
433
- const chatId = msg.chat.id.toString()
434
- const caption = msg.caption?.trim() || ''
435
-
436
- // 权限检查
437
- if (!this._checkPermission(chatId)) {
438
- await this._sendMessage(chatId, '抱歉,您没有权限使用此 Bot。', msg.message_id)
439
- return
440
- }
282
+ async _handleCallback(query) {
283
+ await this._bot.answerCallbackQuery(query.id, { text: '处理中...' })
284
+ }
441
285
 
442
- // 获取最大尺寸的图片
443
- const photo = msg.photo[msg.photo.length - 1]
444
- console.log(`[Telegram] Photo received, file_id: ${photo.file_id}`)
286
+ _checkPermission(chatId) {
287
+ return this.config.allowedChats.length === 0 || this.config.allowedChats.includes(chatId)
288
+ }
445
289
 
446
- try {
447
- // 下载图片
448
- const filePath = await this._downloadFile(photo.file_id, '.jpg', 'telegram_images')
449
- console.log(`[Telegram] Photo saved: ${filePath}`)
450
-
451
- const savedMsg = `收到图片${caption ? ': ' + caption : ''}\n已保存至: ${filePath}`
452
- await this._sendMessage(chatId, savedMsg, msg.message_id)
453
- if(caption){
454
- const message=`图片:${filePath}, ${caption}`
455
- await this._processChat(chatId, message, msg.message_id)
456
- }
457
- // TODO: 调用 AI 视觉能力分析图片
458
- // await this._analyzeImage(chatId, filePath, capti on)
459
- } catch (err) {
460
- console.error('[Telegram] Failed to save photo:', err.message)
461
- await this._sendMessage(chatId, '图片保存失败: ' + err.message, msg.message_id)
462
- }
290
+ async _handlePhoto(msg) {
291
+ const chatId = msg.chat.id.toString()
292
+ if (!this._checkPermission(chatId)) {
293
+ await this._sendMessage(chatId, '抱歉,您没有权限使用此 Bot。', msg.message_id)
294
+ return
463
295
  }
464
296
 
465
- /**
466
- * 处理文档消息
467
- */
468
- async _handleDocument(msg) {
469
- const chatId = msg.chat.id.toString()
470
- const fileName = msg.document.file_name || '未命名文件'
471
- const caption = msg.caption?.trim() || ''
472
-
473
- // 权限检查
474
- if (!this._checkPermission(chatId)) {
475
- await this._sendMessage(chatId, '抱歉,您没有权限使用此 Bot。', msg.message_id)
476
- return
477
- }
478
-
479
- console.log(`[Telegram] Document received: ${fileName}, file_id: ${msg.document.file_id}`)
297
+ const caption = msg.caption?.trim() || ''
298
+ const photo = msg.photo[msg.photo.length - 1]
480
299
 
481
- try {
482
- // 根据文件扩展名确定保存目录和扩展名
483
- const ext = fileName.includes('.') ? fileName.split('.').pop() : 'bin'
484
- const filePath = await this._downloadFile(msg.document.file_id, ext, 'telegram_documents')
485
- console.log(`[Telegram] Document saved: ${filePath}`)
486
-
487
- const savedMsg = `收到文件: ${fileName}\n已保存至: ${filePath}${caption ? '\n\n说明: ' + caption : ''}`
488
- await this._sendMessage(chatId, savedMsg, msg.message_id)
489
- if(caption){
490
- const message=`文件:${filePath}, ${caption}`
491
- await this._processChat(chatId, message, msg.message_id)
492
- }
493
- } catch (err) {
494
- console.error('[Telegram] Failed to save document:', err.message)
495
- await this._sendMessage(chatId, '文件保存失败: ' + err.message, msg.message_id)
300
+ try {
301
+ const filePath = await this._downloadFile(photo.file_id, '.jpg', 'telegram_images')
302
+ await this._sendMessage(chatId, `收到图片${caption ? ': ' + caption : ''}\n已保存至: ${filePath}`, msg.message_id)
303
+ if (caption) {
304
+ await this._processChat(chatId, `图片:${filePath}, ${caption}`, msg.message_id)
496
305
  }
306
+ } catch (err) {
307
+ console.error('[Telegram] Failed to save photo:', err.message)
308
+ await this._sendMessage(chatId, '图片保存失败: ' + err.message, msg.message_id)
497
309
  }
310
+ }
498
311
 
499
- /**
500
- * 下载文件
501
- * @param {string} fileId - Telegram 文件 ID
502
- * @param {string} ext - 文件扩展名
503
- * @param {string} subDir - 子目录名
504
- * @returns {Promise<string>} 保存的文件路径
505
- */
506
- async _downloadFile(fileId, ext, subDir) {
507
- return new Promise((resolve, reject) => {
508
- const path = require('path')
509
- const fs = require('fs')
510
-
511
- // 创建保存目录
512
- const saveDir = path.join(process.cwd(), '.agent', 'data', subDir)
513
- if (!fs.existsSync(saveDir)) {
514
- fs.mkdirSync(saveDir, { recursive: true })
515
- }
516
-
517
- // 生成文件名
518
- const fileName = `${Date.now()}_${Math.random().toString(36).substring(7)}.${ext}`
519
- const filePath = path.join(saveDir, fileName)
520
-
521
- // 下载文件
522
- this._bot.downloadFile(fileId, saveDir)
523
- .then((savedPath) => {
524
- // 重命名为期望的文件名
525
- const finalPath = path.join(saveDir, fileName)
526
- if (savedPath !== finalPath) {
527
- fs.renameSync(savedPath, finalPath)
528
- }
529
- resolve(filePath)
530
- })
531
- .catch(reject)
532
- })
312
+ async _handleDocument(msg) {
313
+ const chatId = msg.chat.id.toString()
314
+ if (!this._checkPermission(chatId)) {
315
+ await this._sendMessage(chatId, '抱歉,您没有权限使用此 Bot。', msg.message_id)
316
+ return
533
317
  }
534
318
 
535
- /**
536
- * 清除会话
537
- */
538
- _clearSession(chatId) {
539
- // 清除 SessionPlugin 中的会话(会触发 session:deleted 事件)
540
- if (this._sessionPlugin) {
541
- const sessionId = `telegram_${chatId}`
542
- this._sessionPlugin.deleteSession(sessionId)
319
+ const fileName = msg.document.file_name || '未命名文件'
320
+ const caption = msg.caption?.trim() || ''
321
+ const ext = fileName.includes('.') ? fileName.split('.').pop() : 'bin'
322
+
323
+ try {
324
+ const filePath = await this._downloadFile(msg.document.file_id, ext, 'telegram_documents')
325
+ await this._sendMessage(chatId, `收到文件: ${fileName}\n已保存至: ${filePath}${caption ? '\n\n说明: ' + caption : ''}`, msg.message_id)
326
+ if (caption) {
327
+ await this._processChat(chatId, `文件:${filePath}, ${caption}`, msg.message_id)
543
328
  }
329
+ } catch (err) {
330
+ console.error('[Telegram] Failed to save document:', err.message)
331
+ await this._sendMessage(chatId, '文件保存失败: ' + err.message, msg.message_id)
544
332
  }
333
+ }
545
334
 
546
- /**
547
- * 发送消息
548
- */
549
- async _sendMessage(chatId, text, replyToMessageId = null) {
550
- if (!this._bot) return
551
- return this._bot.sendMessage(chatId, text, {
552
- reply_to_message_id: replyToMessageId,
553
- })
554
- }
335
+ async _downloadFile(fileId, ext, subDir) {
336
+ const path = require('path')
337
+ const fs = require('fs')
338
+ const saveDir = path.join(process.cwd(), '.agent', 'data', subDir)
339
+ if (!fs.existsSync(saveDir)) fs.mkdirSync(saveDir, { recursive: true })
555
340
 
556
- /**
557
- * 获取插件状态
558
- */
559
- getStatus() {
560
- // 从 SessionPlugin 获取 Telegram 相关会话
561
- let sessions = []
562
- if (this._sessionPlugin) {
563
- const allSessions = this._sessionPlugin.listSessions()
564
- sessions = allSessions
565
- .filter(s => s.id.startsWith('telegram_'))
566
- .map(s => ({
567
- chatId: s.id.replace('telegram_', ''),
568
- historyLength: s.messageCount,
569
- lastActive: s.lastActive
570
- }))
571
- }
341
+ const fileName = `${Date.now()}_${Math.random().toString(36).substring(7)}.${ext}`
342
+ const filePath = path.join(saveDir, fileName)
572
343
 
573
- return {
574
- connected: !!this._bot,
575
- sessionCount: sessions.length,
576
- sessions,
577
- config: {
578
- groupMode: this.config.groupMode,
579
- prefix: this.config.prefix,
580
- allowedChatsCount: this.config.allowedChats.length
581
- }
582
- }
583
- }
344
+ const savedPath = await this._bot.downloadFile(fileId, saveDir)
345
+ if (savedPath !== filePath) fs.renameSync(savedPath, filePath)
346
+ return filePath
347
+ }
584
348
 
585
- /**
586
- * 停止 Bot
587
- */
588
- stopBot() {
589
- if (this._bot) {
590
- this._bot.stopPolling()
591
- this._bot = null
592
- console.log('[Telegram] Bot stopped')
593
- }
349
+ _clearSession(chatId) {
350
+ if (this._sessionPlugin) {
351
+ this._sessionPlugin.deleteSession(`telegram_${chatId}`)
594
352
  }
353
+ }
595
354
 
596
- reload(framework) {
597
- this._framework = framework
598
- if (this.config.botToken) {
599
- this.stopBot()
600
- this._initBot()
601
- }
602
- }
355
+ async _sendMessage(chatId, text, replyToMessageId = null) {
356
+ if (!this._bot) return
357
+ return this._bot.sendMessage(chatId, text, { reply_to_message_id: replyToMessageId })
358
+ }
603
359
 
604
- /**
605
- * 启动 Bot(用于重新启用时)
606
- */
607
- start(framework) {
608
- if (this.config.botToken && !this._bot) {
609
- this._initBot()
360
+ getStatus() {
361
+ let sessions = []
362
+ if (this._sessionPlugin) {
363
+ sessions = this._sessionPlugin.listSessions()
364
+ .filter(s => s.id.startsWith('telegram_'))
365
+ .map(s => ({
366
+ chatId: s.id.replace('telegram_', ''),
367
+ historyLength: s.messageCount,
368
+ lastActive: s.lastActive
369
+ }))
370
+ }
371
+ return {
372
+ connected: !!this._bot,
373
+ sessionCount: sessions.length,
374
+ sessions,
375
+ config: {
376
+ groupMode: this.config.groupMode,
377
+ prefix: this.config.prefix,
378
+ allowedChatsCount: this.config.allowedChats.length
610
379
  }
611
380
  }
381
+ }
612
382
 
613
- uninstall(framework) {
614
- // 销毁所有 session agents
615
- for (const agent of this._sessionAgents.values()) {
616
- agent.destroy()
617
- }
618
- this._sessionAgents.clear()
383
+ stopBot() {
384
+ if (this._bot) {
385
+ this._bot.stopPolling()
386
+ this._bot = null
387
+ console.log('[Telegram] Bot stopped')
388
+ }
389
+ }
619
390
 
391
+ reload(framework) {
392
+ this._framework = framework
393
+ if (this.config.botToken) {
620
394
  this.stopBot()
621
- if (this._sessionPlugin && this._sessionDeleteHandler) {
622
- this._sessionPlugin.off('session:deleted', this._sessionDeleteHandler)
623
- this._sessionDeleteHandler = null
624
- }
625
- this._sessionPlugin = null
626
- this._framework = null
395
+ this._initBot()
396
+ }
397
+ }
398
+
399
+ uninstall() {
400
+ for (const agent of this._sessionAgents.values()) {
401
+ agent.destroy()
402
+ }
403
+ this._sessionAgents.clear()
404
+ this.stopBot()
405
+ if (this._sessionPlugin && this._sessionDeleteHandler) {
406
+ this._sessionPlugin.off('session:deleted', this._sessionDeleteHandler)
407
+ this._sessionDeleteHandler = null
627
408
  }
409
+ this._sessionPlugin = null
410
+ this._framework = null
628
411
  }
629
412
  }
413
+
414
+ module.exports = { TelegramPlugin }