refactor: unify web agent notice event routing

This commit is contained in:
jxxghp
2026-08-24 07:54:05 +08:00
parent da9f1d297a
commit 4e44deb0fa
8 changed files with 170 additions and 165 deletions
+107
View File
@@ -1,4 +1,5 @@
import asyncio
import copy
import uuid
from dataclasses import dataclass, field
from datetime import datetime, timedelta
@@ -6,6 +7,8 @@ from queue import Queue
from threading import Lock
from typing import Awaitable, Callable, Dict, Iterable, List, Optional, Tuple, Union
from app.runtime.log import logger
from app.schemas.message import Message
from app.schemas.types import NotificationChannel
from app.runtime.tasks import get_task_registry
@@ -177,6 +180,8 @@ agent_interaction_manager = AgentInteractionManager()
_WEB_AGENT_EDIT_QUEUES: dict[str, list[Queue[dict]]] = {}
_WEB_AGENT_EDIT_LOCK = Lock()
_WEB_AGENT_MESSAGE_QUEUES: dict[str, list[Queue[Message]]] = {}
_WEB_AGENT_MESSAGE_LOCK = Lock()
_ChannelAdminResolver = Callable[[Optional[dict]], Iterable[Union[str, int]]]
_CHANNEL_ADMIN_RESOLVERS: dict[str, _ChannelAdminResolver] = {}
_WEB_AGENT_BACKGROUND_TASKS: set[asyncio.Task[object]] = set()
@@ -371,6 +376,108 @@ def build_web_agent_message_update_event(
}
def extract_web_agent_message_from_event_data(data: dict) -> Optional[Message]:
"""
从 NoticeMessage 事件数据中提取 WebAgent 通知。
:param data: NoticeMessage 事件数据,兼容扁平字段和 message 包装格式
:return: WebAgent 通知,不属于 WebAgent 或数据无效时返回 None
"""
if not isinstance(data, dict):
return None
try:
message = data.get("message")
if isinstance(message, Message):
message = message
elif isinstance(message, dict):
message_data = copy.deepcopy(message)
message_data.pop("type", None)
message = Message(**message_data)
else:
message_data = copy.deepcopy(data)
message_data.pop("type", None)
message_data.pop("current_time", None)
message = Message(**message_data)
except Exception as err:
logger.debug(f"解析WebAgent通知事件失败: {err}")
return None
channel = message.channel
channel_value = channel.value if isinstance(channel, NotificationChannel) else channel
if channel_value != NotificationChannel.WebAgent.value:
return None
return message
def is_web_agent_message_for_user(message: Message, user_id: str) -> bool:
"""
判断 NoticeMessage 事件是否属于当前 WebAgent 用户。
:param message: NoticeMessage 中的通知消息
:param user_id: 当前登录用户 ID
:return: 可被本次 WebAgent 请求消费时返回 True
"""
try:
target_user = message.userid
return target_user is None or str(target_user) == str(user_id)
except Exception:
return False
def _get_web_agent_message_user_id(message: Message) -> Optional[str]:
"""返回 WebAgent 通知的目标用户 ID,无目标时返回 None。"""
try:
channel = message.channel
channel_value = channel.value if isinstance(channel, NotificationChannel) else channel
if channel_value != NotificationChannel.WebAgent.value:
return None
user_id = message.userid
return str(user_id) if user_id is not None else None
except Exception:
return None
def dispatch_web_agent_message_event(event: object) -> None:
"""将 WebAgent NoticeMessage 分发给正在等待的请求队列。"""
event_data = getattr(event, "event_data", None)
data = event_data if isinstance(event_data, dict) else {}
message = extract_web_agent_message_from_event_data(data)
if not message:
return
with _WEB_AGENT_MESSAGE_LOCK:
user_id = _get_web_agent_message_user_id(message)
if user_id is None:
queues = [
message_queue
for user_queues in _WEB_AGENT_MESSAGE_QUEUES.values()
for message_queue in user_queues
]
else:
queues = list(_WEB_AGENT_MESSAGE_QUEUES.get(user_id) or [])
for message_queue in queues:
message_queue.put(message)
def attach_web_agent_message_queue(user_id: str, message_queue: Queue[Message]) -> None:
"""为当前 WebAgent 请求挂载通知收集队列。"""
with _WEB_AGENT_MESSAGE_LOCK:
_WEB_AGENT_MESSAGE_QUEUES.setdefault(str(user_id), []).append(message_queue)
def detach_web_agent_message_queue(user_id: str, message_queue: Queue[Message]) -> None:
"""移除当前 WebAgent 请求的通知收集队列。"""
with _WEB_AGENT_MESSAGE_LOCK:
queues = _WEB_AGENT_MESSAGE_QUEUES.get(str(user_id))
if not queues:
return
_WEB_AGENT_MESSAGE_QUEUES[str(user_id)] = [
item for item in queues if item is not message_queue
]
if not _WEB_AGENT_MESSAGE_QUEUES[str(user_id)]:
_WEB_AGENT_MESSAGE_QUEUES.pop(str(user_id), None)
def attach_web_agent_edit_queue(user_id: str, edit_queue: Queue[dict]) -> None:
"""
为当前 WebAgent 请求挂载原消息编辑事件队列。