mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-06-21 15:36:37 +08:00
add: query_doctor_report agent tool
This commit is contained in:
126
app/agent/tools/impl/query_doctor_report.py
Normal file
126
app/agent/tools/impl/query_doctor_report.py
Normal file
@@ -0,0 +1,126 @@
|
||||
"""查询 MoviePilot Doctor 诊断报告工具。"""
|
||||
|
||||
import json
|
||||
from typing import Any, Optional, Type
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from app.agent.tools.base import MoviePilotTool
|
||||
from app.agent.tools.tags import ToolTag
|
||||
from app.doctor import run_doctor
|
||||
from app.log import logger
|
||||
|
||||
|
||||
class QueryDoctorReportInput(BaseModel):
|
||||
"""查询 Doctor 诊断报告工具的输入参数模型。"""
|
||||
|
||||
explanation: Optional[str] = Field(
|
||||
None,
|
||||
description="Clear explanation of why this tool is being used in the current context",
|
||||
)
|
||||
deep: Optional[bool] = Field(
|
||||
False,
|
||||
description=(
|
||||
"Whether to run deeper checks. When true, doctor may perform slower environment probes "
|
||||
"such as PostgreSQL TCP connectivity checks."
|
||||
),
|
||||
)
|
||||
include_details: Optional[bool] = Field(
|
||||
True,
|
||||
description=(
|
||||
"Whether to include full doctor findings with details and context. Set false for a compact "
|
||||
"summary when only overall status and finding titles are needed."
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class QueryDoctorReportTool(MoviePilotTool):
|
||||
"""
|
||||
Doctor 离线诊断报告查询工具。
|
||||
"""
|
||||
|
||||
name: str = "query_doctor_report"
|
||||
tags: list[str] = [
|
||||
ToolTag.Read,
|
||||
ToolTag.System,
|
||||
ToolTag.Admin,
|
||||
]
|
||||
description: str = (
|
||||
"Run MoviePilot Doctor in read-only mode and return a structured diagnostic report for troubleshooting. "
|
||||
"Use this tool when analyzing startup failures, Docker/runtime issues, port conflicts, dependency problems, "
|
||||
"database health, frontend assets, safe mode, or recent log error clues. This tool never applies fixes."
|
||||
)
|
||||
require_admin: bool = True
|
||||
args_schema: Type[BaseModel] = QueryDoctorReportInput
|
||||
|
||||
def get_tool_message(self, **kwargs) -> Optional[str]:
|
||||
"""根据查询参数生成友好的提示消息。"""
|
||||
if kwargs.get("deep"):
|
||||
return "运行 Doctor 深度诊断"
|
||||
return "运行 Doctor 诊断"
|
||||
|
||||
@staticmethod
|
||||
def _compact_report(report: dict[str, Any]) -> dict[str, Any]:
|
||||
"""压缩诊断报告,保留 Agent 判断问题所需的核心字段。"""
|
||||
return {
|
||||
"schema_version": report.get("schema_version"),
|
||||
"status": report.get("status"),
|
||||
"generated_at": report.get("generated_at"),
|
||||
"version": report.get("version"),
|
||||
"environment": report.get("environment"),
|
||||
"summary": report.get("summary"),
|
||||
"findings": [
|
||||
{
|
||||
"id": item.get("id"),
|
||||
"severity": item.get("severity"),
|
||||
"status": item.get("status"),
|
||||
"title": item.get("title"),
|
||||
"fixable": item.get("fixable"),
|
||||
"fixed": item.get("fixed"),
|
||||
}
|
||||
for item in report.get("findings") or []
|
||||
if isinstance(item, dict)
|
||||
],
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _run_doctor_report(deep: bool = False) -> dict[str, Any]:
|
||||
"""在线程池中运行只读 Doctor 诊断。"""
|
||||
return run_doctor(deep=bool(deep)).to_dict()
|
||||
|
||||
async def run(
|
||||
self,
|
||||
deep: Optional[bool] = False,
|
||||
include_details: Optional[bool] = True,
|
||||
**kwargs,
|
||||
) -> str:
|
||||
"""
|
||||
运行只读 Doctor 诊断并返回 JSON 字符串。
|
||||
"""
|
||||
logger.info(
|
||||
f"执行工具: {self.name}, deep={bool(deep)}, include_details={bool(include_details)}"
|
||||
)
|
||||
try:
|
||||
report = await self.run_blocking("default", self._run_doctor_report, bool(deep))
|
||||
if not include_details:
|
||||
report = self._compact_report(report)
|
||||
return json.dumps(
|
||||
{
|
||||
"success": True,
|
||||
"deep": bool(deep),
|
||||
"include_details": bool(include_details),
|
||||
"report": report,
|
||||
},
|
||||
ensure_ascii=False,
|
||||
indent=2,
|
||||
default=str,
|
||||
)
|
||||
except Exception as err:
|
||||
logger.error(f"查询 Doctor 诊断报告失败: {err}", exc_info=True)
|
||||
return json.dumps(
|
||||
{
|
||||
"success": False,
|
||||
"message": f"查询 Doctor 诊断报告时发生错误: {str(err)}",
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
Reference in New Issue
Block a user