mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 07:27:15 +08:00
fix(ci): restore lint and architecture gates
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
# 预识别所有未识别的种子
|
||||
|
||||
Reference in New Issue
Block a user