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
# 预识别所有未识别的种子