mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-04 14:24:58 +08:00
fix: finalize agent architecture ratchets
This commit is contained in:
@@ -17,7 +17,7 @@ from app.agent.tools.tags import ToolTag
|
||||
from app.runtime.settings import get_runtime_setting
|
||||
|
||||
|
||||
class DownloaderOperationInput(BaseModel):
|
||||
class DownloaderOperationInput(BaseModel): # type: ignore[misc]
|
||||
"""下载器操作工具的运行时输入模型。"""
|
||||
|
||||
client: Optional[str] = Field(
|
||||
@@ -35,7 +35,7 @@ class DownloaderOperationInput(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
|
||||
class MediaServerOperationInput(BaseModel):
|
||||
class MediaServerOperationInput(BaseModel): # type: ignore[misc]
|
||||
"""媒体服务器操作工具的运行时输入模型。"""
|
||||
|
||||
server: Optional[str] = Field(
|
||||
@@ -53,7 +53,7 @@ class MediaServerOperationInput(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
|
||||
class DatabaseOperationInput(BaseModel):
|
||||
class DatabaseOperationInput(BaseModel): # type: ignore[misc]
|
||||
"""数据库操作工具的运行时输入模型。"""
|
||||
|
||||
action: str = Field(
|
||||
@@ -300,7 +300,7 @@ def _parse_script_payload(stdout: str) -> dict[str, Any]:
|
||||
def _run_service_script(
|
||||
*,
|
||||
relative_script: str,
|
||||
selector_flag: str,
|
||||
selector_flag: Optional[str],
|
||||
selector_value: Optional[str],
|
||||
action: str,
|
||||
arguments: Dict[str, Any],
|
||||
@@ -317,7 +317,7 @@ def _run_service_script(
|
||||
"--arguments",
|
||||
json.dumps(arguments, ensure_ascii=False, separators=(",", ":")),
|
||||
]
|
||||
if selector_value:
|
||||
if selector_value and selector_flag:
|
||||
command.extend([selector_flag, selector_value])
|
||||
completed = subprocess.run(
|
||||
command,
|
||||
@@ -386,12 +386,12 @@ class DownloaderOperationTool(_ServiceOperationTool):
|
||||
)
|
||||
tags: list[str] = [ToolTag.Download]
|
||||
args_schema: Type[BaseModel] = DownloaderOperationInput
|
||||
_relative_script = "skills/downloader-operation/scripts/mp-downloader.py"
|
||||
_selector_name = "client"
|
||||
_selector_flag = "--client"
|
||||
_blocking_bucket = "downloader"
|
||||
_relative_script: ClassVar[str] = "skills/downloader-operation/scripts/mp-downloader.py"
|
||||
_selector_name: ClassVar[Optional[str]] = "client"
|
||||
_selector_flag: ClassVar[Optional[str]] = "--client"
|
||||
_blocking_bucket: ClassVar[str] = "downloader"
|
||||
|
||||
async def run(
|
||||
async def run( # type: ignore[override]
|
||||
self,
|
||||
action: str,
|
||||
arguments: Optional[Dict[str, Any]] = None,
|
||||
@@ -417,12 +417,12 @@ class MediaServerOperationTool(_ServiceOperationTool):
|
||||
)
|
||||
tags: list[str] = [ToolTag.Media]
|
||||
args_schema: Type[BaseModel] = MediaServerOperationInput
|
||||
_relative_script = "skills/mediaserver-operation/scripts/mp-mediaserver.py"
|
||||
_selector_name = "server"
|
||||
_selector_flag = "--server"
|
||||
_blocking_bucket = "mediaserver"
|
||||
_relative_script: ClassVar[str] = "skills/mediaserver-operation/scripts/mp-mediaserver.py"
|
||||
_selector_name: ClassVar[Optional[str]] = "server"
|
||||
_selector_flag: ClassVar[Optional[str]] = "--server"
|
||||
_blocking_bucket: ClassVar[str] = "mediaserver"
|
||||
|
||||
async def run(
|
||||
async def run( # type: ignore[override]
|
||||
self,
|
||||
action: str,
|
||||
arguments: Optional[Dict[str, Any]] = None,
|
||||
@@ -523,10 +523,10 @@ class DatabaseOperationTool(_ServiceOperationTool):
|
||||
)
|
||||
tags: list[str] = [ToolTag.Admin]
|
||||
args_schema: Type[BaseModel] = DatabaseOperationInput
|
||||
_relative_script = "skills/database-operation/scripts/mp-db.py"
|
||||
_selector_name = None
|
||||
_selector_flag = None
|
||||
_blocking_bucket = "db"
|
||||
_relative_script: ClassVar[str] = "skills/database-operation/scripts/mp-db.py"
|
||||
_selector_name: ClassVar[Optional[str]] = None
|
||||
_selector_flag: ClassVar[Optional[str]] = None
|
||||
_blocking_bucket: ClassVar[str] = "db"
|
||||
|
||||
def get_mcp_input_schema(self) -> dict[str, Any]:
|
||||
"""返回数据库 action 的完整 MCP JSON Schema。"""
|
||||
@@ -539,7 +539,7 @@ class DatabaseOperationTool(_ServiceOperationTool):
|
||||
title=self.name,
|
||||
)
|
||||
|
||||
async def run(
|
||||
async def run( # type: ignore[override]
|
||||
self,
|
||||
action: str,
|
||||
arguments: Optional[Dict[str, Any]] = None,
|
||||
|
||||
@@ -130,7 +130,7 @@ async def read_sites(
|
||||
return await query.list_ordered()
|
||||
|
||||
|
||||
@router.get(
|
||||
@router.get( # type: ignore[misc]
|
||||
"/agent",
|
||||
summary="查询 Agent 可用站点",
|
||||
response_model=List[_SchemaJsonObject],
|
||||
|
||||
@@ -146,7 +146,7 @@ def _list_files(
|
||||
return file_list or []
|
||||
|
||||
|
||||
@router.post(
|
||||
@router.post( # type: ignore[misc]
|
||||
"/agent/list",
|
||||
summary="查询 Agent 可用目录和文件",
|
||||
response_model=List[_SchemaFileItem],
|
||||
|
||||
@@ -43,7 +43,7 @@ async def list_workflows(
|
||||
return await query.list()
|
||||
|
||||
|
||||
@router.get(
|
||||
@router.get( # type: ignore[misc]
|
||||
"/agent",
|
||||
summary="查询 Agent 可用工作流",
|
||||
response_model=List[_SchemaJsonObject],
|
||||
|
||||
@@ -60,7 +60,7 @@ class Site(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class SitePriorityUpdate(BaseModel):
|
||||
class SitePriorityUpdate(BaseModel): # type: ignore[misc]
|
||||
"""站点批量优先级更新项。"""
|
||||
|
||||
id: int = Field(..., description="Persistent site ID returned by site.list.")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# MoviePilot Agent 工具体系重构计划
|
||||
|
||||
> 状态:IN PROGRESS — 本地验收已通过,提交推送与远端 CI 收口
|
||||
> 状态:IN PROGRESS — 全量能力与本地门禁已通过,等待最终修复提交和远端 CI 终态
|
||||
>
|
||||
> 建立日期:2026-08-31
|
||||
>
|
||||
@@ -41,7 +41,7 @@
|
||||
| MCP/HTTP 工具管理 | 存在旧业务工具与同名 first-wins 选择空间 | 与主 Agent 共用严格唯一新目录;重名直接以 TOOL_IDENTITY_AMBIGUOUS 失败 |
|
||||
| 退役代码 | 旧实现仍位于 app/agent/tools/impl | 77 个退役文件已直接删除,其中 72 个工具模块、5 个辅助模块 |
|
||||
| 架构图 | 982 个宿主模块、8,430 条内部依赖边 | 919 个宿主模块、7,680 条内部依赖边,Application/Chain 具体 Adapter 直连仍为 0 |
|
||||
| 工作区状态 | 基线提交 871632af,与 origin/v3 对齐,初始工作区干净 | 生产改动、生成合同、静态检查、全量测试和固定 80% 覆盖率门禁已完成;提交、推送和远端 CI 尚待完成 |
|
||||
| 工作区状态 | 基线提交 871632af,与 origin/v3 对齐,初始工作区干净 | 主体提交 `6d4d7331d` 与复杂度修复 `28298c485` 已推送;生产改动、生成合同、静态检查、全量测试和固定 80% 覆盖率门禁已完成,正在提交 Ruff/mypy 低水位收口并等待远端 CI 终态 |
|
||||
|
||||
## 3. 目标工具分层
|
||||
|
||||
@@ -314,6 +314,10 @@ action,并使用 MoviePilot 已配置的具体服务实例访问其自身 API
|
||||
- 受影响 Agent/Skill/MCP/OpenAPI/音乐/架构回归 247 passed;修复全量发现的工作流管理员门禁、插件分页默认值、模块命名治理、服务工具标签和 Schema 导出清单后,专项回归 40 passed
|
||||
- 完整锁定测试最终通过:7,614 passed、9 skipped;覆盖率按 CI 相同的 8 分片采集并合并,Application 81.88%、Domain 81.01%,通过固定 80% 门禁
|
||||
- 首次推送 `6d4d7331d` 的远端 Pylint 成功;Architecture Contract Gate 在 complexity v2 发现 `plugin.py` 从 999 行增长到 1007 行,合并三个短 import 后恢复到 999 行,本地两套复杂度门禁及 49 项相关回归均通过
|
||||
- 当前活动叶子保持 L9;下一步完成提交前差异审查、提交推送并检查远端 CI 终态
|
||||
- 第二次推送 `28298c485` 的远端 Pylint 成功;Architecture Contract Gate 识别出两处 Ruff 导入排序债务下降尚未固化,以及新增 service tool/Agent 投影端点未显式处理 mypy 既有基础设施告警
|
||||
- 已对新增 Pydantic/ResponseAPIRouter 边界使用精确错误码抑制,补齐 service tool 的 ClassVar 与可选 selector 类型;未通过覆盖基线隐藏任何新增 mypy 错误
|
||||
- Ruff 低水位由 576 降至 574,mypy 低水位由 9,606 降至 9,605;mypy、复杂度 v1/v2、并发、异步阻塞、TaskRegistry owner、服务定位和启动性能全部本地通过
|
||||
- API/Skill/MCP/provider 专项 86 passed,架构与质量门禁专项 127 passed;生成器重建后工作区合同无额外差异
|
||||
- 当前活动叶子保持 L9;下一步提交本轮低水位修复,等待所有远端工作流终态成功后更新为 COMPLETE
|
||||
|
||||
本文件作为本次重构的持续记录,保留阶段状态、实际变更、验证结果、提交状态与已知基线边界。
|
||||
|
||||
@@ -519,7 +519,7 @@
|
||||
"no-any-return": 5,
|
||||
"no-untyped-call": 1,
|
||||
"no-untyped-def": 2,
|
||||
"type-arg": 11
|
||||
"type-arg": 10
|
||||
},
|
||||
"app/api/endpoints/recommend.py": {
|
||||
"attr-defined": 2,
|
||||
|
||||
@@ -579,9 +579,6 @@
|
||||
"app/schemas/response.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/schemas/site.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"app/schemas/subscribe.py": {
|
||||
"I001": 1
|
||||
},
|
||||
@@ -996,9 +993,6 @@
|
||||
"tests/test_site_adapter_collector.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_skill_scripts_security.py": {
|
||||
"I001": 1
|
||||
},
|
||||
"tests/test_skills_command.py": {
|
||||
"E402": 6,
|
||||
"I001": 1
|
||||
|
||||
Reference in New Issue
Block a user