"""统一工具处理器"""
|
|
import json
|
from typing import Dict, List, Any, Optional
|
from config.logger import setup_logging
|
from plugins_func.loadplugins import auto_import_modules
|
|
from .base import ToolType
|
from plugins_func.register import Action, ActionResponse
|
from .unified_tool_manager import ToolManager
|
from .server_plugins import ServerPluginExecutor
|
from .server_mcp import ServerMCPExecutor
|
from .device_iot import DeviceIoTExecutor
|
from .device_mcp import DeviceMCPExecutor
|
from .mcp_endpoint import MCPEndpointExecutor
|
from core.handle.sendAudioHandle import send_display_message
|
|
|
class UnifiedToolHandler:
|
"""统一工具处理器"""
|
|
def __init__(self, conn):
|
self.conn = conn
|
self.config = conn.config
|
self.logger = setup_logging()
|
|
# 创建工具管理器
|
self.tool_manager = ToolManager(conn)
|
|
# 创建各类执行器
|
self.server_plugin_executor = ServerPluginExecutor(conn)
|
self.server_mcp_executor = ServerMCPExecutor(conn)
|
self.device_iot_executor = DeviceIoTExecutor(conn)
|
self.device_mcp_executor = DeviceMCPExecutor(conn)
|
self.mcp_endpoint_executor = MCPEndpointExecutor(conn)
|
|
# 注册执行器
|
self.tool_manager.register_executor(
|
ToolType.SERVER_PLUGIN, self.server_plugin_executor
|
)
|
self.tool_manager.register_executor(
|
ToolType.SERVER_MCP, self.server_mcp_executor
|
)
|
self.tool_manager.register_executor(
|
ToolType.DEVICE_IOT, self.device_iot_executor
|
)
|
self.tool_manager.register_executor(
|
ToolType.DEVICE_MCP, self.device_mcp_executor
|
)
|
self.tool_manager.register_executor(
|
ToolType.MCP_ENDPOINT, self.mcp_endpoint_executor
|
)
|
|
# 初始化标志
|
self.finish_init = False
|
|
async def _initialize(self):
|
"""异步初始化"""
|
try:
|
# 自动导入插件模块
|
auto_import_modules("plugins_func.functions")
|
|
# 初始化服务端MCP
|
await self.server_mcp_executor.initialize()
|
|
# 初始化MCP接入点
|
await self._initialize_mcp_endpoint()
|
|
# 初始化Home Assistant(如果需要)
|
self._initialize_home_assistant()
|
|
self.finish_init = True
|
self.logger.debug("统一工具处理器初始化完成")
|
|
# 输出当前支持的所有工具列表
|
self.current_support_functions()
|
|
except Exception as e:
|
self.logger.error(f"统一工具处理器初始化失败: {e}")
|
|
async def _initialize_mcp_endpoint(self):
|
"""初始化MCP接入点"""
|
try:
|
from .mcp_endpoint import connect_mcp_endpoint
|
|
# 从配置中获取MCP接入点URL
|
mcp_endpoint_url = self.config.get("mcp_endpoint", "")
|
|
if (
|
mcp_endpoint_url
|
and "你的" not in mcp_endpoint_url
|
and mcp_endpoint_url != "null"
|
):
|
self.logger.info(f"正在初始化MCP接入点: {mcp_endpoint_url}")
|
mcp_endpoint_client = await connect_mcp_endpoint(
|
mcp_endpoint_url, self.conn
|
)
|
|
if mcp_endpoint_client:
|
# 将MCP接入点客户端保存到连接对象中
|
self.conn.mcp_endpoint_client = mcp_endpoint_client
|
self.logger.info("MCP接入点初始化成功")
|
else:
|
self.logger.warning("MCP接入点初始化失败")
|
|
except Exception as e:
|
self.logger.error(f"初始化MCP接入点失败: {e}")
|
|
def _initialize_home_assistant(self):
|
"""初始化Home Assistant提示词"""
|
try:
|
from plugins_func.functions.hass_init import append_devices_to_prompt
|
|
append_devices_to_prompt(self.conn)
|
except ImportError:
|
pass # 忽略导入错误
|
except Exception as e:
|
self.logger.error(f"初始化Home Assistant失败: {e}")
|
|
def get_functions(self) -> List[Dict[str, Any]]:
|
"""获取所有工具的函数描述"""
|
return self.tool_manager.get_function_descriptions()
|
|
def current_support_functions(self) -> List[str]:
|
"""获取当前支持的函数名称列表"""
|
func_names = self.tool_manager.get_supported_tool_names()
|
self.logger.info(f"当前支持的函数列表: {func_names}")
|
return func_names
|
|
def upload_functions_desc(self):
|
"""刷新函数描述列表"""
|
self.tool_manager.refresh_tools()
|
self.logger.info("函数描述列表已刷新")
|
|
def has_tool(self, tool_name: str) -> bool:
|
"""检查是否有指定工具"""
|
return self.tool_manager.has_tool(tool_name)
|
|
async def handle_llm_function_call(
|
self, conn, function_call_data: Dict[str, Any]
|
) -> Optional[ActionResponse]:
|
"""处理LLM函数调用"""
|
try:
|
# 处理多函数调用
|
if "function_calls" in function_call_data:
|
responses = []
|
for call in function_call_data["function_calls"]:
|
result = await self.tool_manager.execute_tool(
|
call["name"], call.get("arguments", {})
|
)
|
responses.append(result)
|
return self._combine_responses(responses)
|
|
# 处理单函数调用
|
function_name = function_call_data["name"]
|
arguments = function_call_data.get("arguments", {})
|
|
# 如果arguments是字符串,尝试解析为JSON
|
if isinstance(arguments, str):
|
try:
|
arguments = json.loads(arguments) if arguments else {}
|
except json.JSONDecodeError:
|
self.logger.error(f"无法解析函数参数: {arguments}")
|
return ActionResponse(
|
action=Action.ERROR,
|
response="无法解析函数参数",
|
)
|
|
self.logger.debug(f"调用函数: {function_name}, 参数: {arguments}")
|
|
# 发送工具调用显示消息到设备
|
try:
|
await send_display_message(self.conn, f"% {function_name}")
|
except Exception as e:
|
self.logger.warning(f"发送工具调用显示消息失败: {e}")
|
|
# 执行工具调用
|
result = await self.tool_manager.execute_tool(function_name, arguments)
|
return result
|
|
except Exception as e:
|
self.logger.error(f"处理function call错误: {e}")
|
return ActionResponse(action=Action.ERROR, response=str(e))
|
|
def _combine_responses(self, responses: List[ActionResponse]) -> ActionResponse:
|
"""合并多个函数调用的响应"""
|
if not responses:
|
return ActionResponse(action=Action.NONE, response="无响应")
|
|
# 如果有任何错误,返回第一个错误
|
for response in responses:
|
if response.action == Action.ERROR:
|
return response
|
|
# 合并所有成功的响应
|
contents = []
|
responses_text = []
|
|
for response in responses:
|
if response.content:
|
contents.append(response.content)
|
if response.response:
|
responses_text.append(response.response)
|
|
# 确定最终的动作类型
|
final_action = Action.RESPONSE
|
for response in responses:
|
if response.action == Action.REQLLM:
|
final_action = Action.REQLLM
|
break
|
|
return ActionResponse(
|
action=final_action,
|
result="; ".join(contents) if contents else None,
|
response="; ".join(responses_text) if responses_text else None,
|
)
|
|
async def register_iot_tools(self, descriptors: List[Dict[str, Any]]):
|
"""注册IoT设备工具"""
|
self.device_iot_executor.register_iot_tools(descriptors)
|
self.tool_manager.refresh_tools()
|
self.logger.info(f"注册了{len(descriptors)}个IoT设备的工具")
|
|
def get_tool_statistics(self) -> Dict[str, int]:
|
"""获取工具统计信息"""
|
return self.tool_manager.get_tool_statistics()
|
|
async def cleanup(self):
|
"""清理资源"""
|
try:
|
await self.server_mcp_executor.cleanup()
|
|
# 清理MCP接入点连接
|
if (
|
hasattr(self.conn, "mcp_endpoint_client")
|
and self.conn.mcp_endpoint_client
|
):
|
await self.conn.mcp_endpoint_client.close()
|
|
self.logger.info("工具处理器清理完成")
|
except Exception as e:
|
self.logger.error(f"工具处理器清理失败: {e}")
|