feat(message-processing-status): unified processing status indicator for Telegram, Slack, Discord, Feishu

- Add ChannelCapability.PROCESSING_STATUS and capability detection for supported channels
- Implement mark_message_processing_started/finished in Telegram, Slack, Discord, Feishu modules
  - Telegram: manage typing lifecycle with max duration and explicit stop
  - Slack: add/remove reaction as processing indicator
  - Discord: start/stop typing indicator with async task management
  - Feishu: add/remove reaction for processing status
- Refactor message chain to invoke processing status hooks for supported channels
- Ensure processing status is properly finished on sync and async message handling paths
- Add tests for processing status lifecycle and capability detection across channels
This commit is contained in:
jxxghp
2026-05-15 12:45:41 +08:00
parent 5a06e7b8bc
commit b2a18f9ae4
13 changed files with 1101 additions and 92 deletions

View File

@@ -8,6 +8,7 @@ from datetime import datetime
from enum import Enum
from typing import Any, Callable, Dict, List, Optional
from fastapi.concurrency import run_in_threadpool
from langchain.agents import create_agent
from langchain.agents.middleware import (
SummarizationMiddleware,
@@ -53,6 +54,40 @@ class AgentChain(ChainBase):
pass
def _finish_processing_status(status: Optional[dict], user_id: Optional[str] = None) -> None:
"""结束入站消息的渠道处理状态。"""
if not status:
return
try:
channel = MessageChannel(status.get("channel"))
except Exception:
return
try:
AgentChain().run_module(
"mark_message_processing_finished",
channel=channel,
source=status.get("source"),
userid=status.get("userid") or user_id,
message_id=status.get("message_id"),
chat_id=status.get("chat_id"),
status=status,
)
except Exception as err:
logger.debug(f"结束Agent消息处理状态失败: {err}")
async def _async_finish_processing_status(
status: Optional[dict], user_id: Optional[str] = None
) -> None:
"""
在 Agent worker 中结束渠道处理状态。
渠道收口可能触发外部 API同步实现需切到线程池避免阻塞事件循环。
"""
if not status:
return
await run_in_threadpool(_finish_processing_status, status, user_id)
@dataclass
class _SessionUsageSnapshot:
model: Optional[str] = None
@@ -901,6 +936,7 @@ class _MessageTask:
username: Optional[str] = None
original_message_id: Optional[str] = None
original_chat_id: Optional[str] = None
processing_status: Optional[dict] = None
reply_mode: ReplyMode = ReplyMode.DISPATCH
@@ -987,6 +1023,7 @@ class AgentManager:
username: str = None,
original_message_id: Optional[str] = None,
original_chat_id: Optional[str] = None,
processing_status: Optional[dict] = None,
reply_mode: ReplyMode = ReplyMode.DISPATCH,
) -> str:
"""
@@ -1004,6 +1041,7 @@ class AgentManager:
username=username,
original_message_id=original_message_id,
original_chat_id=original_chat_id,
processing_status=processing_status,
reply_mode=reply_mode,
)
@@ -1062,6 +1100,9 @@ class AgentManager:
except Exception as e:
logger.error(f"处理会话 {session_id} 的消息失败: {e}")
finally:
await _async_finish_processing_status(
task.processing_status, task.user_id
)
queue.task_done()
except asyncio.CancelledError: