foliko 2.0.13 → 2.0.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foliko",
3
- "version": "2.0.13",
3
+ "version": "2.0.15",
4
4
  "description": "简约的插件化 Agent 框架",
5
5
  "main": "src/index.js",
6
6
  "type": "commonjs",
@@ -68,6 +68,8 @@ class WeixinPlugin extends Plugin {
68
68
  // 当前活跃 agent 用 _currentAgent 跟踪
69
69
  this._currentAgent = null
70
70
  this.sessionId=null
71
+ // 防止重复处理的标志
72
+ this._processingMessages = new Set()
71
73
  }
72
74
 
73
75
  install(framework) {
@@ -426,23 +428,43 @@ class WeixinPlugin extends Plugin {
426
428
  // });
427
429
 
428
430
  // 队列完成
431
+ let queueCompletedProcessing = false;
429
432
  sessionScope.on('queue:completed', async () => {
430
- this.stopTypingInterval();
431
- const message=cleanResponse(lineBuffer.value.trim())
432
- if(!message){
433
- const msg = '继续进行下一步';
434
- await agent.sendMessage(msg, { sessionId, priority: 1 });
435
- }else{
436
- await this._sendMessageBatch(originalMsg, userId, message, true);
437
- //log.debug(`[Queue] Remaining buffer: ${lineBuffer.value}`);
433
+ if (queueCompletedProcessing) {
434
+ log.debug(` [queue:completed] 正在处理中,跳过`)
435
+ return
436
+ }
437
+ queueCompletedProcessing = true
438
+ try {
439
+ this.stopTypingInterval();
440
+ const message=cleanResponse(lineBuffer.value.trim())
441
+ if(!message){
442
+ const msg = '继续进行下一步';
443
+ await agent.sendMessage(msg, { sessionId, priority: 1 });
444
+ }else{
445
+ await this._sendMessageBatch(originalMsg, userId, message, true);
446
+ //log.debug(`[Queue] Remaining buffer: ${lineBuffer.value}`);
447
+ }
448
+ lineBuffer.value = '';
449
+ } finally {
450
+ queueCompletedProcessing = false
438
451
  }
439
- lineBuffer.value = '';
440
452
  });
441
453
 
442
454
  // 队列失败
455
+ let queueFailedProcessing = false;
443
456
  sessionScope.on('queue:failed', async ({ error }) => {
444
- this.stopTypingInterval();
445
- await this._sendMessageBatch(originalMsg, userId, error, true);
457
+ if (queueFailedProcessing) {
458
+ log.debug(` [queue:failed] 正在处理中,跳过`)
459
+ return
460
+ }
461
+ queueFailedProcessing = true
462
+ try {
463
+ this.stopTypingInterval();
464
+ await this._sendMessageBatch(originalMsg, userId, error, true);
465
+ } finally {
466
+ queueFailedProcessing = false
467
+ }
446
468
  });
447
469
 
448
470
  this._sessionScopes.set(sessionId, sessionScope);
@@ -499,6 +521,22 @@ class WeixinPlugin extends Plugin {
499
521
  async _handleMessage(msg) {
500
522
  if (!msg || !msg.userId) return
501
523
 
524
+ // 防止重复处理同一消息
525
+ const msgKey = msg.msgId || `${msg.userId}-${msg.type}-${Date.now()}`
526
+ if (this._processingMessages.has(msgKey)) {
527
+ log.debug(` 跳过重复消息: ${msgKey}`)
528
+ return
529
+ }
530
+ this._processingMessages.add(msgKey)
531
+ // 5秒后清理,避免内存泄漏
532
+ setTimeout(() => this._processingMessages.delete(msgKey), 5000)
533
+
534
+ // 忽略机器人自己发送的消息(防止回音室效应)
535
+ if (this._myUserId && msg.userId === this._myUserId) {
536
+ log.debug(` 忽略机器人自己的消息: ${msgKey}`)
537
+ return
538
+ }
539
+
502
540
  const userId = msg.userId
503
541
  // 从 SessionPlugin 获取历史消息数量
504
542
  let messageCount = 0
@@ -579,35 +617,47 @@ class WeixinPlugin extends Plugin {
579
617
  * 处理对话
580
618
  */
581
619
  async _processChat(userId, text, originalMsg) {
582
- // 处理命令
583
- if (text.startsWith('/')) {
584
- await this._handleCommand(userId, text, originalMsg)
620
+ // 防止并发处理同一个用户的消息
621
+ const userKey = `process:${userId}`
622
+ if (this._processingMessages.has(userKey)) {
623
+ log.debug(` 用户 ${userId} 正在处理中,跳过新消息`)
585
624
  return
586
625
  }
626
+ this._processingMessages.add(userKey)
587
627
 
588
- const sessionInfo = this._getSessionAgent(userId)
589
- if (!sessionInfo) {
590
- log.error(' No session agent available')
591
- return
592
- }
593
- const { agent, sessionId } = sessionInfo
628
+ try {
629
+ // 处理命令
630
+ if (text.startsWith('/')) {
631
+ await this._handleCommand(userId, text, originalMsg)
632
+ return
633
+ }
594
634
 
595
- // 发送正在输入状态
596
- this.startTypingInterval()
635
+ const sessionInfo = this._getSessionAgent(userId)
636
+ if (!sessionInfo) {
637
+ log.error(' No session agent available')
638
+ return
639
+ }
640
+ const { agent, sessionId } = sessionInfo
597
641
 
598
- // 预创建或获取 sessionScope(复用监听器)
599
- let sessionScope = this._sessionScopes.get(sessionId)
600
- if (!sessionScope) {
601
- sessionScope = this._setupSessionScopeListeners(agent, sessionId, originalMsg, userId)
602
- }
642
+ // 发送正在输入状态
643
+ this.startTypingInterval()
603
644
 
604
- try {
605
- await agent.sendMessage(text, { sessionId, priority: 1 })
606
- } catch (err) {
607
- log.error(' Chat error:', err.message)
608
- await this._sendMessageBatch(originalMsg, userId, `发生错误:${err.message}`, true)
645
+ // 预创建或获取 sessionScope(复用监听器)
646
+ let sessionScope = this._sessionScopes.get(sessionId)
647
+ if (!sessionScope) {
648
+ sessionScope = this._setupSessionScopeListeners(agent, sessionId, originalMsg, userId)
649
+ }
650
+
651
+ try {
652
+ await agent.sendMessage(text, { sessionId, priority: 1 })
653
+ } catch (err) {
654
+ log.error(' Chat error:', err.message)
655
+ await this._sendMessageBatch(originalMsg, userId, `发生错误:${err.message}`, true)
656
+ } finally {
657
+ this.stopTypingInterval()
658
+ }
609
659
  } finally {
610
- this.stopTypingInterval()
660
+ this._processingMessages.delete(userKey)
611
661
  }
612
662
  }
613
663