refactor(chain): 处理链功能域 mixin 化,清理未使用导入并根治兼容层循环导入

- ChainBase 拆分为 RecognitionMixin/MessageProcessingMixin/NotificationMixin
- TransferChain 拆分为 7 个功能 mixin(_mixins.py),SubscribeChain 音乐订阅域拆出 _music.py
- 斜杠命令交互四件套收敛为 InteractionChainMixin 委托,会话管理器移至 application 层,chain 层不再 re-export
- 模块基础类收敛到 app/modules/_base(notification/mediaserver 语义重命名)
- 清理 app/chain/__init__.py 24 个未使用导入,修正 49 处测试 patch 目标到实际命名空间
- 兼容层 legacy 符号不再并入 __all__,根治 schemas 初始化反向拉起 application.transfer 的循环导入
- 修复 bangumi 集数为字符串时 set_bangumi_info 抛 TypeError
- 新增重复代码等架构门禁测试;capability 清单校验排除下划线内部目录
This commit is contained in:
jxxghp
2026-08-16 16:30:16 +08:00
parent 24671f8f18
commit 7e851dbfa7
102 changed files with 6041 additions and 5888 deletions
+15 -11
View File
@@ -11,8 +11,12 @@ from pathlib import Path
from typing import Any, Optional, Dict, Union, List, Tuple
from urllib.parse import unquote, urlparse
from app.agent.orchestrator import agent_manager
from app.agent.llm import AgentCapabilityManager, LLMHelper
from app.application.agent import (
get_agent_manager,
is_audio_input_available,
supports_image_input,
transcribe_audio,
)
from app.chain import ChainBase
from app.chain.download import DownloadChain
from app.chain.media import MediaChain
@@ -68,7 +72,7 @@ class MessageChain(ChainBase):
return
clear_task = None
try:
clear_task = agent_manager.clear_session(session_id=session_id, user_id=str(userid))
clear_task = get_agent_manager().clear_session(session_id=session_id, user_id=str(userid))
asyncio.run_coroutine_threadsafe(
clear_task,
global_vars.loop,
@@ -346,7 +350,7 @@ class MessageChain(ChainBase):
if not session_info:
return False
session_id, _ = session_info
if not agent_manager.matches_secret_confirmation(
if not get_agent_manager().matches_secret_confirmation(
session_id,
str(userid),
channel=channel.value,
@@ -966,7 +970,7 @@ class MessageChain(ChainBase):
if session_id:
clear_task = None
try:
clear_task = agent_manager.clear_session(
clear_task = get_agent_manager().clear_session(
session_id=session_id, user_id=str(userid)
)
asyncio.run_coroutine_threadsafe(
@@ -1015,7 +1019,7 @@ class MessageChain(ChainBase):
session_id, _ = session_info
try:
future = asyncio.run_coroutine_threadsafe(
agent_manager.stop_current_task(session_id=session_id),
get_agent_manager().stop_current_task(session_id=session_id),
global_vars.loop,
)
stopped = future.result(timeout=10)
@@ -1180,7 +1184,7 @@ class MessageChain(ChainBase):
return
session_id, _ = session_info
status = agent_manager.get_session_status(session_id=session_id)
status = get_agent_manager().get_session_status(session_id=session_id)
self.post_message(
Notification(
channel=channel,
@@ -1254,7 +1258,7 @@ class MessageChain(ChainBase):
# 将可直接输入给 LLM 的附件统一转换为 data URL
original_images = images
all_files = list(files or [])
if images and LLMHelper.supports_image_input(
if images and supports_image_input(
provider=settings.LLM_PROVIDER,
model=settings.LLM_MODEL,
):
@@ -1333,7 +1337,7 @@ class MessageChain(ChainBase):
process_kwargs["has_audio_input"] = True
# 在事件循环中处理
asyncio.run_coroutine_threadsafe(
agent_manager.process_message(**process_kwargs),
get_agent_manager().process_message(**process_kwargs),
global_vars.loop,
)
return True
@@ -1353,7 +1357,7 @@ class MessageChain(ChainBase):
"""
if not audio_refs:
return None
if not AgentCapabilityManager.is_audio_input_available():
if not is_audio_input_available():
logger.warning("音频输入能力未配置或未启用,跳过语音识别")
return None
@@ -1460,7 +1464,7 @@ class MessageChain(ChainBase):
)
continue
transcript = AgentCapabilityManager.transcribe_audio(
transcript = transcribe_audio(
content=content, filename=filename
)
if transcript: