fix(ci): restore lint and architecture gates

This commit is contained in:
jxxghp
2026-08-22 10:23:18 +08:00
parent 9273d68aa7
commit 508bf0bc38
8 changed files with 84 additions and 89 deletions
+3 -7
View File
@@ -5,15 +5,11 @@ from typing import Any, Optional, Tuple
from fastapi.concurrency import run_in_threadpool
from app.agent.policy import sanitize_for_host
from app.agent.policy.sanitizer import sanitize_for_host
from app.chain import ChainBase
from app.runtime.log import logger
from app.schemas.message import Message
from app.schemas.message import (
MessageResponse,
ChannelCapabilityManager,
ChannelCapability,
)
from app.schemas.message import Message, MessageResponse
from app.schemas.notification import ChannelCapabilityManager, ChannelCapability
from app.schemas.types import NotificationChannel, MessageType
+2 -2
View File
@@ -21,7 +21,7 @@ from langgraph.checkpoint.memory import InMemorySaver
from app.agent.callback import StreamingHandler
from app.agent.contracts import ReplyMode, build_display_message
from app.agent.llm import LLMHelper
from app.agent.llm.helper import LLMHelper
from app.agent.llm.server_tools import ServerToolRegistry
from app.agent.memory import memory_manager
from app.agent.middleware.activity_log import (
@@ -51,7 +51,7 @@ from app.agent.middleware.subagents import (
from app.agent.middleware.tool_selection import ToolSelectorMiddleware
from app.agent.middleware.usage import UsageMiddleware
from app.agent.prompt import prompt_manager
from app.agent.policy import (
from app.agent.policy.contracts import (
AuthSource,
PrincipalType,
ToolOrigin,
+18 -13
View File
@@ -65,6 +65,23 @@ def _check_auth(api_key: Optional[str]) -> Optional[JSONResponse]:
return None
def _manager_execution_error(error: BaseException) -> JSONResponse:
"""把 AgentManager 稳定错误映射为 Anthropic 兼容错误响应。"""
if _is_manager_unavailable(error):
return _anthropic_error_response(
"MoviePilot AI agent is unavailable.",
503,
error_type="api_error",
)
if _is_manager_queue_full(error):
return _anthropic_error_response(
str(error),
429,
error_type="rate_limit_error",
)
return _anthropic_error_response(str(error), 500, error_type="api_error")
async def _stream_anthropic_response(
manager,
session_id: str,
@@ -241,19 +258,7 @@ async def messages(
stream_mode=False,
)
except Exception as exc:
if _is_manager_unavailable(exc):
return _anthropic_error_response(
"MoviePilot AI agent is unavailable.",
503,
error_type="api_error",
)
if _is_manager_queue_full(exc):
return _anthropic_error_response(
str(exc),
429,
error_type="rate_limit_error",
)
return _anthropic_error_response(str(exc), 500, error_type="api_error")
return _manager_execution_error(exc)
finally:
await manager.clear_session(session_id=session_id, user_id=session_id)
+26 -40
View File
@@ -351,6 +351,30 @@ def _is_manager_queue_full(error: BaseException) -> bool:
return getattr(error, "code", None) == "agent_manager_queue_full"
def _manager_execution_error(error: BaseException) -> JSONResponse:
"""把 AgentManager 稳定错误映射为 OpenAI 兼容错误响应。"""
if _is_manager_unavailable(error):
return _error_response(
"MoviePilot AI agent is unavailable.",
503,
error_type="server_error",
code="ai_agent_unavailable",
)
if _is_manager_queue_full(error):
return _error_response(
str(error),
429,
error_type="rate_limit_error",
code="ai_agent_queue_full",
)
return _error_response(
str(error),
500,
error_type="server_error",
code="agent_execution_failed",
)
async def _run_managed_agent(
*,
manager,
@@ -550,26 +574,7 @@ async def chat_completions(
stream_mode=False,
)
except Exception as exc:
if _is_manager_unavailable(exc):
return _error_response(
"MoviePilot AI agent is unavailable.",
503,
error_type="server_error",
code="ai_agent_unavailable",
)
if _is_manager_queue_full(exc):
return _error_response(
str(exc),
429,
error_type="rate_limit_error",
code="ai_agent_queue_full",
)
return _error_response(
str(exc),
500,
error_type="server_error",
code="agent_execution_failed",
)
return _manager_execution_error(exc)
finally:
if not use_server_session:
await manager.clear_session(session_id=session_id, user_id=session_key)
@@ -657,26 +662,7 @@ async def responses(
stream_mode=False,
)
except Exception as exc:
if _is_manager_unavailable(exc):
return _error_response(
"MoviePilot AI agent is unavailable.",
503,
error_type="server_error",
code="ai_agent_unavailable",
)
if _is_manager_queue_full(exc):
return _error_response(
str(exc),
429,
error_type="rate_limit_error",
code="ai_agent_queue_full",
)
return _error_response(
str(exc),
500,
error_type="server_error",
code="agent_execution_failed",
)
return _manager_execution_error(exc)
finally:
if not payload.user:
await manager.clear_session(session_id=session_id, user_id=session_key)
+26 -22
View File
@@ -1353,6 +1353,28 @@ class SubscribeChain(MusicSubscribeMixin, InteractionChainMixin, ChainBase):
"""
return cls._subscription_query().exists(mediainfo, meta)
def _acquire_run_lock(
self,
operation: str,
progress_callback: Optional[Callable[..., None]],
) -> bool:
"""获取订阅任务锁,超时时统一记录并结束本轮进度。"""
if self._rlock.acquire(blocking=True, timeout=self._LOCK_TIMOUT):
logger.debug(f"{operation} lock acquired at {datetime.now()}")
return True
operation_label = {"search": "搜索", "match": "匹配"}[operation]
progress_text = {
"search": "订阅搜索锁等待超时,已跳过本轮",
"match": "订阅匹配锁等待超时,已跳过本轮",
}[operation]
logger.error(f"订阅{operation_label}锁等待超时,已中止本轮执行")
if progress_callback:
progress_callback(
value=100,
text=progress_text,
)
return False
def search(
self,
sid: Optional[int] = None,
@@ -1370,17 +1392,8 @@ class SubscribeChain(MusicSubscribeMixin, InteractionChainMixin, ChainBase):
"""
lock_acquired = False
try:
if lock_acquired := self._rlock.acquire(
blocking=True, timeout=self._LOCK_TIMOUT
):
logger.debug(f"search lock acquired at {datetime.now()}")
else:
logger.error("订阅搜索锁等待超时,已中止本轮执行")
if progress_callback:
progress_callback(
value=100,
text="订阅搜索锁等待超时,已跳过本轮",
)
lock_acquired = self._acquire_run_lock("search", progress_callback)
if not lock_acquired:
return
subscribeoper = SubscribeOper()
@@ -1820,17 +1833,8 @@ class SubscribeChain(MusicSubscribeMixin, InteractionChainMixin, ChainBase):
lock_acquired = False
try:
if lock_acquired := self._rlock.acquire(
blocking=True, timeout=self._LOCK_TIMOUT
):
logger.debug(f"match lock acquired at {datetime.now()}")
else:
logger.error("订阅匹配锁等待超时,已中止本轮执行")
if progress_callback:
progress_callback(
value=100,
text="订阅匹配锁等待超时,已跳过本轮",
)
lock_acquired = self._acquire_run_lock("match", progress_callback)
if not lock_acquired:
return
# 预识别所有未识别的种子
+6 -2
View File
@@ -13,8 +13,8 @@
"runtime_to_db": [],
"workflow_to_db": []
},
"edge_count": 6313,
"edge_sha256": "25292ce04e33206f713eb24cff2397931124fcb22f55ab0d78f94314581161d4",
"edge_count": 6317,
"edge_sha256": "11978842b2fd9bd6ccec86c01c5f1b9389d959bc53aab5e16e29e3c121b3dab9",
"edges": [
"app -> app.runtime",
"app -> app.runtime.compat",
@@ -169,11 +169,13 @@
"app.adapters.web.security.access -> app.schemas.token",
"app.agent.callback -> app.agent",
"app.agent.callback -> app.agent.policy",
"app.agent.callback -> app.agent.policy.sanitizer",
"app.agent.callback -> app.chain",
"app.agent.callback -> app.runtime",
"app.agent.callback -> app.runtime.log",
"app.agent.callback -> app.schemas",
"app.agent.callback -> app.schemas.message",
"app.agent.callback -> app.schemas.notification",
"app.agent.callback -> app.schemas.types",
"app.agent.capabilities.adapter -> app.agent",
"app.agent.capabilities.adapter -> app.agent.capabilities",
@@ -303,6 +305,7 @@
"app.agent.orchestrator -> app.agent.callback",
"app.agent.orchestrator -> app.agent.contracts",
"app.agent.orchestrator -> app.agent.llm",
"app.agent.orchestrator -> app.agent.llm.helper",
"app.agent.orchestrator -> app.agent.llm.server_tools",
"app.agent.orchestrator -> app.agent.mcp",
"app.agent.orchestrator -> app.agent.memory",
@@ -319,6 +322,7 @@
"app.agent.orchestrator -> app.agent.middleware.tool_selection",
"app.agent.orchestrator -> app.agent.middleware.usage",
"app.agent.orchestrator -> app.agent.policy",
"app.agent.orchestrator -> app.agent.policy.contracts",
"app.agent.orchestrator -> app.agent.prompt",
"app.agent.orchestrator -> app.agent.runtime",
"app.agent.orchestrator -> app.agent.runtime_loader",
+1 -1
View File
@@ -7,7 +7,7 @@ import langchain.agents as langchain_agents
if not hasattr(langchain_agents, "create_agent"):
langchain_agents.create_agent = lambda *args, **kwargs: None
from app.agent import _ThinkTagStripper
from app.agent.orchestrator import _ThinkTagStripper
from app.agent.callback import StreamingHandler
from app.agent.middleware.subagents import is_subagent_stream_metadata
from app.agent.tools.base import MoviePilotTool
+2 -2
View File
@@ -11,9 +11,9 @@ import pytest
from app.domain.context import MediaInfo, Context, TorrentInfo
from app.domain.metainfo import MetaInfo
from app.modules.telegram import TelegramModule
from app.modules.telegram.module import TelegramModule
from app.modules.telegram.telegram import Telegram
from app.schemas import Message
from app.schemas.message import Message
from app.schemas.types import NotificationChannel
from app.schemas.types import MediaType