mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 23:47:41 +08:00
feat:Agent插件工具发现
This commit is contained in:
@@ -13,6 +13,7 @@ from app.agent.tools.impl.query_subscribes import QuerySubscribesTool
|
|||||||
from app.agent.tools.impl.search_media import SearchMediaTool
|
from app.agent.tools.impl.search_media import SearchMediaTool
|
||||||
from app.agent.tools.impl.search_torrents import SearchTorrentsTool
|
from app.agent.tools.impl.search_torrents import SearchTorrentsTool
|
||||||
from app.agent.tools.impl.send_message import SendMessageTool
|
from app.agent.tools.impl.send_message import SendMessageTool
|
||||||
|
from app.core.plugin import PluginManager
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from .base import MoviePilotTool
|
from .base import MoviePilotTool
|
||||||
|
|
||||||
@@ -39,6 +40,7 @@ class MoviePilotToolFactory:
|
|||||||
QueryMediaLibraryTool,
|
QueryMediaLibraryTool,
|
||||||
SendMessageTool
|
SendMessageTool
|
||||||
]
|
]
|
||||||
|
# 创建内置工具
|
||||||
for ToolClass in tool_definitions:
|
for ToolClass in tool_definitions:
|
||||||
tool = ToolClass(
|
tool = ToolClass(
|
||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
@@ -47,5 +49,36 @@ class MoviePilotToolFactory:
|
|||||||
tool.set_message_attr(channel=channel, source=source, username=username)
|
tool.set_message_attr(channel=channel, source=source, username=username)
|
||||||
tool.set_callback_handler(callback_handler=callback_handler)
|
tool.set_callback_handler(callback_handler=callback_handler)
|
||||||
tools.append(tool)
|
tools.append(tool)
|
||||||
|
|
||||||
|
# 加载插件提供的工具
|
||||||
|
plugin_tools_count = 0
|
||||||
|
plugin_tools_info = PluginManager().get_plugin_agent_tools()
|
||||||
|
for plugin_info in plugin_tools_info:
|
||||||
|
plugin_id = plugin_info.get("plugin_id")
|
||||||
|
plugin_name = plugin_info.get("plugin_name")
|
||||||
|
tool_classes = plugin_info.get("tools", [])
|
||||||
|
for ToolClass in tool_classes:
|
||||||
|
try:
|
||||||
|
# 验证工具类是否继承自 MoviePilotTool
|
||||||
|
if not issubclass(ToolClass, MoviePilotTool):
|
||||||
|
logger.warning(f"插件 {plugin_name}({plugin_id}) 提供的工具类 {ToolClass.__name__} 未继承自 MoviePilotTool,已跳过")
|
||||||
|
continue
|
||||||
|
# 创建工具实例
|
||||||
|
tool = ToolClass(
|
||||||
|
session_id=session_id,
|
||||||
|
user_id=user_id
|
||||||
|
)
|
||||||
|
tool.set_message_attr(channel=channel, source=source, username=username)
|
||||||
|
tool.set_callback_handler(callback_handler=callback_handler)
|
||||||
|
tools.append(tool)
|
||||||
|
plugin_tools_count += 1
|
||||||
|
logger.debug(f"成功加载插件 {plugin_name}({plugin_id}) 的工具: {ToolClass.__name__}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"加载插件 {plugin_name}({plugin_id}) 的工具 {ToolClass.__name__} 失败: {str(e)}")
|
||||||
|
|
||||||
|
builtin_tools_count = len(tool_definitions)
|
||||||
|
if plugin_tools_count > 0:
|
||||||
|
logger.info(f"成功创建 {len(tools)} 个MoviePilot工具(内置工具: {builtin_tools_count} 个,插件工具: {plugin_tools_count} 个)")
|
||||||
|
else:
|
||||||
logger.info(f"成功创建 {len(tools)} 个MoviePilot工具")
|
logger.info(f"成功创建 {len(tools)} 个MoviePilot工具")
|
||||||
return tools
|
return tools
|
||||||
|
|||||||
@@ -745,6 +745,36 @@ class PluginManager(metaclass=Singleton):
|
|||||||
logger.error(f"获取插件 {plugin_id} 动作出错:{str(e)}")
|
logger.error(f"获取插件 {plugin_id} 动作出错:{str(e)}")
|
||||||
return ret_actions
|
return ret_actions
|
||||||
|
|
||||||
|
def get_plugin_agent_tools(self, pid: Optional[str] = None) -> List[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
获取插件智能体工具
|
||||||
|
[{
|
||||||
|
"plugin_id": "插件ID",
|
||||||
|
"plugin_name": "插件名称",
|
||||||
|
"tools": [ToolClass1, ToolClass2, ...]
|
||||||
|
}]
|
||||||
|
"""
|
||||||
|
ret_tools = []
|
||||||
|
# 创建字典快照避免并发修改
|
||||||
|
running_plugins_snapshot = dict(self._running_plugins)
|
||||||
|
for plugin_id, plugin in running_plugins_snapshot.items():
|
||||||
|
if pid and pid != plugin_id:
|
||||||
|
continue
|
||||||
|
if hasattr(plugin, "get_agent_tools") and ObjectUtils.check_method(plugin.get_agent_tools):
|
||||||
|
try:
|
||||||
|
if not plugin.get_state():
|
||||||
|
continue
|
||||||
|
tools = plugin.get_agent_tools()
|
||||||
|
if tools:
|
||||||
|
ret_tools.append({
|
||||||
|
"plugin_id": plugin_id,
|
||||||
|
"plugin_name": plugin.plugin_name,
|
||||||
|
"tools": tools
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"获取插件 {plugin_id} 智能体工具出错:{str(e)}")
|
||||||
|
return ret_tools
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_plugin_remote_entry(plugin_id: str, dist_path: str) -> str:
|
def get_plugin_remote_entry(plugin_id: str, dist_path: str) -> str:
|
||||||
"""
|
"""
|
||||||
|
|||||||
+15
-1
@@ -1,6 +1,6 @@
|
|||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, List, Dict, Tuple, Optional
|
from typing import Any, List, Dict, Tuple, Optional, Type
|
||||||
|
|
||||||
from app.chain import ChainBase
|
from app.chain import ChainBase
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
@@ -200,6 +200,20 @@ class _PluginBase(metaclass=ABCMeta):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def get_agent_tools(self) -> List[Type]:
|
||||||
|
"""
|
||||||
|
获取插件智能体工具
|
||||||
|
返回工具类列表,每个工具类必须继承自 MoviePilotTool
|
||||||
|
[ToolClass1, ToolClass2, ...]
|
||||||
|
|
||||||
|
对工具类的要求:
|
||||||
|
1、工具类必须继承自 app.agent.tools.base.MoviePilotTool
|
||||||
|
2、工具类需要实现 run 方法(异步方法)
|
||||||
|
3、工具类需要定义 name 和 description 属性
|
||||||
|
4、工具类可以定义 args_schema 来指定输入参数模型
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def stop_service(self):
|
def stop_service(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user