foliko 1.0.40 → 1.0.43

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,407 @@ 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
+ **命令执行规范:**
32
+ - 执行 npx skills add / npx skills remove / npx skills list 命令时,必须自动添加参数:-a openclaw -y
33
+ - 禁止添加 -g 参数
34
+ - 例如:npx skills add xxx 应该执行为 npx skills add xxx -a openclaw -y`
35
+
36
+ this.config = {
37
+ botToken: config.botToken || process.env.TELEGRAM_BOT_TOKEN,
38
+ allowedChats: config.allowedChats || [],
39
+ groupMode: config.groupMode || false,
40
+ prefix: config.prefix || '/'
46
41
  }
47
42
 
48
- install(framework) {
49
- this._framework = framework
43
+ this._framework = null
44
+ this._bot = null
45
+ this._sessionPlugin = null
46
+ this._sessionDeleteHandler = null
47
+ this._sessionAgents = new Map()
48
+ }
49
+
50
+ install(framework) {
51
+ this._framework = framework
52
+ return this
53
+ }
54
+
55
+ start(framework) {
56
+ if (!this.config.botToken) {
57
+ console.warn('[Telegram] No bot token. Set TELEGRAM_BOT_TOKEN env var.')
50
58
  return this
51
59
  }
52
60
 
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')
61
+ this._framework = framework
62
+ this._sessionPlugin = framework.pluginManager.get('session')
61
63
 
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
- }
64
+ if (this._sessionPlugin) {
65
+ this._sessionDeleteHandler = (sessionId) => {
66
+ if (sessionId.startsWith('telegram_')) {
67
+ console.log(`[Telegram] Session deleted: ${sessionId}`)
69
68
  }
70
- this._sessionPlugin.on('session:deleted', this._sessionDeleteHandler)
71
69
  }
72
-
73
- this._initBot()
74
- return this
70
+ this._sessionPlugin.on('session:deleted', this._sessionDeleteHandler)
75
71
  }
76
72
 
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
- })
73
+ this._initBot()
74
+ return this
75
+ }
101
76
 
102
- // 监听消息
103
- this._bot.on('message', (msg) => this._handleMessage(msg))
77
+ _initBot() {
78
+ try {
79
+ const TelegramBot = require('node-telegram-bot-api')
80
+ this._bot = new TelegramBot(this.config.botToken, { polling: true })
104
81
 
105
- // 监听编辑消息
106
- this._bot.on('edit_message', (msg) => this._handleEdit(msg))
82
+ console.log('[Telegram] Bot started successfully')
107
83
 
108
- // 监听回调
109
- this._bot.on('callback_query', (query) => this._handleCallback(query))
84
+ this._bot.setMyCommands([
85
+ { command: 'start', description: '显示帮助信息' },
86
+ { command: 'clear', description: '清除对话历史' },
87
+ { command: 'history', description: '查看对话状态' }
88
+ ]).catch((err) => {
89
+ console.error('[Telegram] Failed to register commands:', err.message)
90
+ })
110
91
 
111
- // 监听错误
112
- this._bot.on('polling_error', (err) => {
113
- console.error('[Telegram] Polling error:', err.message)
114
- })
92
+ this._bot.on('message', (msg) => this._handleMessage(msg))
93
+ this._bot.on('edit_message', (msg) => this._handleEdit(msg))
94
+ this._bot.on('callback_query', (query) => this._handleCallback(query))
95
+ this._bot.on('polling_error', (err) => console.error('[Telegram] Polling error:', err.message))
96
+ this._bot.on('error', (err) => console.error('[Telegram] Bot error:', err.message))
115
97
 
116
- this._bot.on('error', (err) => {
117
- console.error('[Telegram] Bot error:', err.message)
98
+ if (this._framework) {
99
+ this._framework.on('agent:created', (agent) => {
100
+ console.log('[Telegram] New agent created:', agent.name)
101
+ })
102
+ this._framework.on('scheduler:reminder', async (data) => {
103
+ await this._handleScheduledReminder(data)
118
104
  })
105
+ }
106
+ } catch (err) {
107
+ console.error('[Telegram] Failed to initialize bot:', err.message)
108
+ }
109
+ }
119
110
 
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
- }
111
+ async _handleScheduledReminder(data) {
112
+ const { taskName, message, sessionId } = data
113
+ const reminderText = `🔔 [${taskName}]\n\n${message}`
132
114
 
115
+ if (sessionId && sessionId.startsWith('telegram_')) {
116
+ const chatId = sessionId.replace('telegram_', '')
117
+ try {
118
+ await this._bot.sendMessage(chatId, reminderText)
119
+ console.log(`[Telegram] Reminder sent to chat ${chatId}`)
133
120
  } catch (err) {
134
- console.error('[Telegram] Failed to initialize bot:', err.message)
121
+ console.error(`[Telegram] Failed to send reminder:`, err.message)
135
122
  }
123
+ return
136
124
  }
137
125
 
138
- /**
139
- * 处理定时提醒
140
- */
141
- async _handleScheduledReminder(data) {
142
- const { taskName, message, sessionId } = data
143
-
144
- // 构建提醒消息
145
- const reminderText = `🔔 [${taskName}]\n\n${message}`
126
+ if (this._sessionPlugin) {
127
+ const sessions = this._sessionPlugin.listSessions()
128
+ .filter(s => s.id.startsWith('telegram_'))
129
+ .sort((a, b) => new Date(b.lastActive).getTime() - new Date(a.lastActive).getTime())
146
130
 
147
- // 如果有 sessionId telegram 类型的,发送到对应 chat
148
- if (sessionId && sessionId.startsWith('telegram_')) {
149
- const chatId = sessionId.replace('telegram_', '')
131
+ if (sessions.length > 0) {
132
+ const chatId = sessions[0].id.replace('telegram_', '')
150
133
  try {
151
134
  await this._bot.sendMessage(chatId, reminderText)
152
- console.log(`[Telegram] Reminder sent to chat ${chatId}`)
135
+ console.log(`[Telegram] Reminder sent to recent chat ${chatId}`)
153
136
  } catch (err) {
154
137
  console.error(`[Telegram] Failed to send reminder:`, err.message)
155
138
  }
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
139
  }
180
140
  }
141
+ }
181
142
 
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
143
+ _getMainAgent() {
144
+ if (this._framework._mainAgent) return this._framework._mainAgent
145
+ const agents = this._framework._agents || []
146
+ return agents.length > 0 ? agents[agents.length - 1] : null
147
+ }
148
+
149
+ _getSessionAgent(chatId) {
150
+ if (this._sessionAgents.has(chatId)) {
151
+ return { agent: this._sessionAgents.get(chatId), sessionId: `telegram_${chatId}` }
198
152
  }
199
153
 
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
- }
154
+ const agent = this._framework.createSessionAgent(`telegram_${chatId}`, {
155
+ systemPrompt: this.systemPrompt,
156
+ sharedPrompt: `工作目录: {{WORK_DIR}}`,
157
+ metadata: { WORK_DIR: process.cwd() }
158
+ })
159
+ this._sessionAgents.set(chatId, agent)
214
160
 
215
- // 创建新 agent
216
- const agent = this._framework.createSessionAgent(`telegram_${chatId}`, {
217
- systemPrompt: this.systemPrompt
161
+ if (this._sessionPlugin) {
162
+ this._sessionPlugin.getOrCreateSession(`telegram_${chatId}`, {
163
+ metadata: { platform: 'telegram', chatId }
218
164
  })
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
165
  }
233
166
 
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
167
+ return { agent, sessionId: `telegram_${chatId}` }
168
+ }
255
169
 
256
- const text = msg.text.trim()
170
+ async _handleMessage(msg) {
171
+ if (!msg || !msg.chat) return
172
+ const chatId = msg.chat.id.toString()
257
173
 
258
- // 命令处理
259
- if (text.startsWith(this.config.prefix)) {
260
- await this._handleCommand(msg)
261
- return
262
- }
174
+ if (msg.photo) { await this._handlePhoto(msg); return }
175
+ if (msg.document) { await this._handleDocument(msg); return }
176
+ if (!msg.text) return
263
177
 
264
- // 群组模式检查
265
- if (msg.chat.type === 'group' || msg.chat.type === 'supergroup') {
266
- if (!this.config.groupMode) return
267
- }
178
+ const text = msg.text.trim()
179
+ if (text.startsWith(this.config.prefix)) {
180
+ await this._handleCommand(msg)
181
+ return
182
+ }
268
183
 
269
- // 权限检查
270
- if (!this._checkPermission(chatId)) {
271
- await this._sendMessage(chatId, '抱歉,您没有权限使用此 Bot。', msg.message_id)
272
- return
273
- }
184
+ if (msg.chat.type === 'group' || msg.chat.type === 'supergroup') {
185
+ if (!this.config.groupMode) return
186
+ }
274
187
 
275
- // 处理对话
276
- await this._processChat(chatId, text, msg.message_id)
188
+ if (!this._checkPermission(chatId)) {
189
+ await this._sendMessage(chatId, '抱歉,您没有权限使用此 Bot。', msg.message_id)
190
+ return
277
191
  }
278
192
 
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':
193
+ await this._processChat(chatId, text, msg.message_id)
194
+ }
195
+
196
+ async _handleCommand(msg) {
197
+ const chatId = msg.chat.id.toString()
198
+ const text = msg.text.trim()
199
+ const parts = text.split(' ')
200
+ const command = parts[0].substring(1)
201
+ const args = parts.slice(1).join(' ')
202
+
203
+ switch (command.toLowerCase()) {
204
+ case 'start':
205
+ await this._sendMessage(chatId,
206
+ '👋 欢迎使用 AI 助手!\n\n直接发送消息即可与我对话。\n\n可用命令:\n/start - 显示帮助\n/clear - 清除对话历史\n/history - 查看历史消息数',
207
+ msg.message_id)
208
+ break
209
+ case 'clear':
210
+ this._clearSession(chatId)
211
+ await this._sendMessage(chatId, '✅ 对话历史已清除', msg.message_id)
212
+ break
213
+ case 'history':
214
+ if (this._sessionPlugin) {
215
+ const session = this._sessionPlugin.getSession(`telegram_${chatId}`)
216
+ const sessions = this._sessionPlugin.listSessions().filter(s => s.id.startsWith('telegram_'))
291
217
  await this._sendMessage(chatId,
292
- '👋 欢迎使用 AI 助手!\n\n' +
293
- '直接发送消息即可与我对话,我会尽力帮助您。\n\n' +
294
- '可用命令:\n' +
295
- '/start - 显示帮助\n' +
296
- '/clear - 清除对话历史\n' +
297
- '/history - 查看历史消息数',
218
+ `📊 当前状态\n\n会话数:${sessions.length}\n历史消息:${session?.messages?.length || 0}\n最后活跃:${session?.lastActive?.toLocaleString() || '无'}`,
298
219
  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
- }
220
+ } else {
221
+ await this._sendMessage(chatId, '❌ 会话服务不可用', msg.message_id)
222
+ }
223
+ break
224
+ default:
225
+ await this._processChat(chatId, text, msg.message_id)
326
226
  }
227
+ }
327
228
 
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
- }
229
+ async _processChat(chatId, text, replyToMessageId) {
230
+ const sessionInfo = this._getSessionAgent(chatId)
231
+ if (!sessionInfo) {
232
+ await this._sendMessage(chatId, '❌ AI 服务未初始化', replyToMessageId)
233
+ return
234
+ }
339
235
 
340
- const { agent, sessionId } = sessionInfo
236
+ const { agent, sessionId } = sessionInfo
341
237
 
342
- // 使用 SessionPlugin 添加用户消息到历史
343
- if (this._sessionPlugin) {
344
- this._sessionPlugin.addMessage(sessionId, { role: 'user', content: text })
345
- }
238
+ if (this._sessionPlugin) {
239
+ this._sessionPlugin.addMessage(sessionId, { role: 'user', content: text })
240
+ }
346
241
 
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
- }
242
+ let thinkingMsg
243
+ try {
244
+ thinkingMsg = await this._bot.sendMessage(chatId, '🤔 思考中...', {
245
+ reply_to_message_id: replyToMessageId
246
+ })
247
+ } catch (err) {
248
+ console.error('[Telegram] Send thinking error:', err.message)
249
+ return
250
+ }
357
251
 
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
- }
252
+ try {
253
+ let fullResponse = ''
254
+ for await (const chunk of agent.chatStream(text, { sessionId })) {
255
+ if (chunk.type === 'text' && chunk.text) {
256
+ fullResponse += chunk.text
257
+ if (fullResponse.length % 100 === 0) {
258
+ try {
259
+ await this._bot.editMessageText(`📝 ${escapeMarkdown(fullResponse)}▌`, {
260
+ chat_id: chatId,
261
+ message_id: thinkingMsg.message_id
262
+ })
263
+ } catch (e) { /* ignore */ }
380
264
  }
381
265
  }
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
266
  }
403
- }
404
267
 
405
- /**
406
- * 处理编辑消息
407
- */
408
- async _handleEdit(msg) {
409
- // 支持编辑后重新处理
410
- }
268
+ if (this._sessionPlugin) {
269
+ this._sessionPlugin.addMessage(sessionId, { role: 'assistant', content: fullResponse })
270
+ }
411
271
 
412
- /**
413
- * 处理回调查询
414
- */
415
- async _handleCallback(query) {
416
- await this._bot.answerCallbackQuery(query.id, {
417
- text: '处理中...'
272
+ const safeResponse = escapeMarkdown(fullResponse) || '抱歉,我没有收到有效的回复。'
273
+ await this._bot.editMessageText(safeResponse, {
274
+ chat_id: chatId,
275
+ message_id: thinkingMsg.message_id,
276
+ parse_mode: 'MarkdownV2'
277
+ })
278
+ } catch (err) {
279
+ console.error('[Telegram] Chat error:', err)
280
+ await this._bot.editMessageText(escapeMarkdown(`❌ 发生错误:${err.message}`), {
281
+ chat_id: chatId,
282
+ message_id: thinkingMsg.message_id
418
283
  })
419
284
  }
285
+ }
420
286
 
421
- /**
422
- * 权限检查
423
- */
424
- _checkPermission(chatId) {
425
- if (this.config.allowedChats.length === 0) return true
426
- return this.config.allowedChats.includes(chatId)
427
- }
287
+ async _handleEdit(msg) { /* 支持编辑后重新处理 */ }
428
288
 
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
- }
289
+ async _handleCallback(query) {
290
+ await this._bot.answerCallbackQuery(query.id, { text: '处理中...' })
291
+ }
441
292
 
442
- // 获取最大尺寸的图片
443
- const photo = msg.photo[msg.photo.length - 1]
444
- console.log(`[Telegram] Photo received, file_id: ${photo.file_id}`)
293
+ _checkPermission(chatId) {
294
+ return this.config.allowedChats.length === 0 || this.config.allowedChats.includes(chatId)
295
+ }
445
296
 
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
- }
297
+ async _handlePhoto(msg) {
298
+ const chatId = msg.chat.id.toString()
299
+ if (!this._checkPermission(chatId)) {
300
+ await this._sendMessage(chatId, '抱歉,您没有权限使用此 Bot。', msg.message_id)
301
+ return
463
302
  }
464
303
 
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}`)
304
+ const caption = msg.caption?.trim() || ''
305
+ const photo = msg.photo[msg.photo.length - 1]
480
306
 
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)
307
+ try {
308
+ const filePath = await this._downloadFile(photo.file_id, '.jpg', 'telegram_images')
309
+ await this._sendMessage(chatId, `收到图片${caption ? ': ' + caption : ''}\n已保存至: ${filePath}`, msg.message_id)
310
+ if (caption) {
311
+ await this._processChat(chatId, `图片:${filePath}, ${caption}`, msg.message_id)
496
312
  }
313
+ } catch (err) {
314
+ console.error('[Telegram] Failed to save photo:', err.message)
315
+ await this._sendMessage(chatId, '图片保存失败: ' + err.message, msg.message_id)
497
316
  }
317
+ }
498
318
 
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
- })
319
+ async _handleDocument(msg) {
320
+ const chatId = msg.chat.id.toString()
321
+ if (!this._checkPermission(chatId)) {
322
+ await this._sendMessage(chatId, '抱歉,您没有权限使用此 Bot。', msg.message_id)
323
+ return
533
324
  }
534
325
 
535
- /**
536
- * 清除会话
537
- */
538
- _clearSession(chatId) {
539
- // 清除 SessionPlugin 中的会话(会触发 session:deleted 事件)
540
- if (this._sessionPlugin) {
541
- const sessionId = `telegram_${chatId}`
542
- this._sessionPlugin.deleteSession(sessionId)
326
+ const fileName = msg.document.file_name || '未命名文件'
327
+ const caption = msg.caption?.trim() || ''
328
+ const ext = fileName.includes('.') ? fileName.split('.').pop() : 'bin'
329
+
330
+ try {
331
+ const filePath = await this._downloadFile(msg.document.file_id, ext, 'telegram_documents')
332
+ await this._sendMessage(chatId, `收到文件: ${fileName}\n已保存至: ${filePath}${caption ? '\n\n说明: ' + caption : ''}`, msg.message_id)
333
+ if (caption) {
334
+ await this._processChat(chatId, `文件:${filePath}, ${caption}`, msg.message_id)
543
335
  }
336
+ } catch (err) {
337
+ console.error('[Telegram] Failed to save document:', err.message)
338
+ await this._sendMessage(chatId, '文件保存失败: ' + err.message, msg.message_id)
544
339
  }
340
+ }
545
341
 
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
- }
342
+ async _downloadFile(fileId, ext, subDir) {
343
+ const path = require('path')
344
+ const fs = require('fs')
345
+ const saveDir = path.join(process.cwd(), '.agent', 'data', subDir)
346
+ if (!fs.existsSync(saveDir)) fs.mkdirSync(saveDir, { recursive: true })
555
347
 
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
- }
348
+ const fileName = `${Date.now()}_${Math.random().toString(36).substring(7)}.${ext}`
349
+ const filePath = path.join(saveDir, fileName)
572
350
 
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
- }
351
+ const savedPath = await this._bot.downloadFile(fileId, saveDir)
352
+ if (savedPath !== filePath) fs.renameSync(savedPath, filePath)
353
+ return filePath
354
+ }
584
355
 
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
- }
356
+ _clearSession(chatId) {
357
+ if (this._sessionPlugin) {
358
+ this._sessionPlugin.deleteSession(`telegram_${chatId}`)
594
359
  }
360
+ }
595
361
 
596
- reload(framework) {
597
- this._framework = framework
598
- if (this.config.botToken) {
599
- this.stopBot()
600
- this._initBot()
601
- }
602
- }
362
+ async _sendMessage(chatId, text, replyToMessageId = null) {
363
+ if (!this._bot) return
364
+ return this._bot.sendMessage(chatId, text, { reply_to_message_id: replyToMessageId })
365
+ }
603
366
 
604
- /**
605
- * 启动 Bot(用于重新启用时)
606
- */
607
- start(framework) {
608
- if (this.config.botToken && !this._bot) {
609
- this._initBot()
367
+ getStatus() {
368
+ let sessions = []
369
+ if (this._sessionPlugin) {
370
+ sessions = this._sessionPlugin.listSessions()
371
+ .filter(s => s.id.startsWith('telegram_'))
372
+ .map(s => ({
373
+ chatId: s.id.replace('telegram_', ''),
374
+ historyLength: s.messageCount,
375
+ lastActive: s.lastActive
376
+ }))
377
+ }
378
+ return {
379
+ connected: !!this._bot,
380
+ sessionCount: sessions.length,
381
+ sessions,
382
+ config: {
383
+ groupMode: this.config.groupMode,
384
+ prefix: this.config.prefix,
385
+ allowedChatsCount: this.config.allowedChats.length
610
386
  }
611
387
  }
388
+ }
612
389
 
613
- uninstall(framework) {
614
- // 销毁所有 session agents
615
- for (const agent of this._sessionAgents.values()) {
616
- agent.destroy()
617
- }
618
- this._sessionAgents.clear()
390
+ stopBot() {
391
+ if (this._bot) {
392
+ this._bot.stopPolling()
393
+ this._bot = null
394
+ console.log('[Telegram] Bot stopped')
395
+ }
396
+ }
619
397
 
398
+ reload(framework) {
399
+ this._framework = framework
400
+ if (this.config.botToken) {
620
401
  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
402
+ this._initBot()
403
+ }
404
+ }
405
+
406
+ uninstall() {
407
+ for (const agent of this._sessionAgents.values()) {
408
+ agent.destroy()
409
+ }
410
+ this._sessionAgents.clear()
411
+ this.stopBot()
412
+ if (this._sessionPlugin && this._sessionDeleteHandler) {
413
+ this._sessionPlugin.off('session:deleted', this._sessionDeleteHandler)
414
+ this._sessionDeleteHandler = null
627
415
  }
416
+ this._sessionPlugin = null
417
+ this._framework = null
628
418
  }
629
419
  }
420
+
421
+ module.exports = { TelegramPlugin }