feat: Introduce unified tooling system for plugins and MCP

- Added a new `tooling` module to define a unified model for tool declarations, invocations, and execution results, facilitating compatibility between plugins, legacy actions, and MCP tools.
- Implemented `ToolProvider` interface for various tool providers including built-in tools, MCP tools, and plugin runtime tools.
- Enhanced `MCPManager` and `MCPConnection` to support unified tool invocation and execution results.
- Updated `ComponentRegistry` and related classes to accommodate the new tool specifications and descriptions.
- Refactored existing components to utilize the new tooling system, ensuring backward compatibility with legacy actions.
- Improved error handling and logging for tool invocations across different providers.
This commit is contained in:
DrSmoothl
2026-03-30 23:11:56 +08:00
parent 898b693fe0
commit dc2bf02a42
35 changed files with 1663 additions and 6756 deletions

View File

@@ -1,124 +1,163 @@
"""
MaiSaka built-in tool definitions.
"""
"""Maisaka 内置工具声明。"""
from typing import List
from copy import deepcopy
from typing import Any, Dict, List
from src.llm_models.payload_content.tool_option import ToolOption, ToolParamType
from src.core.tooling import ToolSpec, build_tool_detailed_description
from src.llm_models.payload_content.tool_option import ToolDefinitionInput
def create_builtin_tools() -> List[ToolOption]:
"""Create built-in tools exposed to the main chat-loop model."""
from src.llm_models.payload_content.tool_option import ToolOptionBuilder
def _build_tool_spec(
name: str,
brief_description: str,
parameters_schema: Dict[str, Any] | None = None,
detailed_description: str = "",
) -> ToolSpec:
"""构建单个内置工具声明。
tools: List[ToolOption] = []
Args:
name: 工具名称。
brief_description: 简要描述。
parameters_schema: 参数 Schema。
detailed_description: 详细描述;为空时自动根据参数生成。
wait_builder = ToolOptionBuilder()
wait_builder.set_name("wait")
wait_builder.set_description("Pause speaking and wait for the user to provide more input.")
wait_builder.add_param(
name="seconds",
param_type=ToolParamType.INTEGER,
description="How many seconds to wait before timing out.",
required=True,
enum_values=None,
Returns:
ToolSpec: 构建完成的工具声明。
"""
normalized_schema = deepcopy(parameters_schema) if parameters_schema is not None else None
return ToolSpec(
name=name,
brief_description=brief_description,
detailed_description=(
detailed_description.strip()
or build_tool_detailed_description(normalized_schema)
),
parameters_schema=normalized_schema,
provider_name="maisaka_builtin",
provider_type="builtin",
)
tools.append(wait_builder.build())
reply_builder = ToolOptionBuilder()
reply_builder.set_name("reply")
reply_builder.set_description(
"Generate and emit a visible reply based on the current thought. "
"You must specify the target user msg_id to reply to."
)
reply_builder.add_param(
name="msg_id",
param_type=ToolParamType.STRING,
description="The msg_id of the specific user message that this reply should target.",
required=True,
enum_values=None,
)
reply_builder.add_param(
name="quote",
param_type=ToolParamType.BOOLEAN,
description="Whether the visible reply should be sent as a quoted reply to the target msg_id.",
required=False,
enum_values=None,
)
reply_builder.add_param(
name="unknown_words",
param_type=ToolParamType.ARRAY,
description="Optional list of words or phrases that may need jargon lookup before replying.",
required=False,
enum_values=None,
items_schema={"type": "string"},
)
tools.append(reply_builder.build())
query_jargon_builder = ToolOptionBuilder()
query_jargon_builder.set_name("query_jargon")
query_jargon_builder.set_description(
"Query the meanings of one or more jargon words in the current chat context."
)
query_jargon_builder.add_param(
name="words",
param_type=ToolParamType.ARRAY,
description="A list of words or phrases to query from the jargon store.",
required=True,
enum_values=None,
items_schema={"type": "string"},
)
tools.append(query_jargon_builder.build())
query_person_info_builder = ToolOptionBuilder()
query_person_info_builder.set_name("query_person_info")
query_person_info_builder.set_description(
"Query profile and memory information about a specific person by person name, nickname, or user ID."
)
query_person_info_builder.add_param(
name="person_name",
param_type=ToolParamType.STRING,
description="The person's name, nickname, or user ID to search for.",
required=True,
enum_values=None,
)
query_person_info_builder.add_param(
name="limit",
param_type=ToolParamType.INTEGER,
description="Maximum number of matched person records to return. Defaults to 3.",
required=False,
enum_values=None,
)
tools.append(query_person_info_builder.build())
no_reply_builder = ToolOptionBuilder()
no_reply_builder.set_name("no_reply")
no_reply_builder.set_description("Do not emit a visible reply this round and continue thinking.")
tools.append(no_reply_builder.build())
stop_builder = ToolOptionBuilder()
stop_builder.set_name("stop")
stop_builder.set_description("Stop the current inner loop and return control to the outer chat flow.")
tools.append(stop_builder.build())
send_emoji_builder = ToolOptionBuilder()
send_emoji_builder.set_name("send_emoji")
send_emoji_builder.set_description(
"Send an emoji sticker to help express emotions. "
"You should specify the emotion type to select an appropriate emoji."
)
send_emoji_builder.add_param(
name="emotion",
param_type=ToolParamType.STRING,
description="The emotion type for selecting an appropriate emoji (e.g., 'happy', 'sad', 'angry', 'surprised', etc.).",
required=False,
enum_values=None,
)
tools.append(send_emoji_builder.build())
return tools
def get_builtin_tools() -> List[ToolOption]:
"""Return built-in tools."""
return create_builtin_tools()
def create_builtin_tool_specs() -> List[ToolSpec]:
"""创建 Maisaka 内置工具声明列表。
Returns:
List[ToolSpec]: 内置工具声明列表。
"""
return [
_build_tool_spec(
name="wait",
brief_description="暂停当前对话并等待用户新的输入。",
parameters_schema={
"type": "object",
"properties": {
"seconds": {
"type": "integer",
"description": "等待的秒数。",
},
},
"required": ["seconds"],
},
),
_build_tool_spec(
name="reply",
brief_description="根据当前思考生成并发送一条可见回复。",
parameters_schema={
"type": "object",
"properties": {
"msg_id": {
"type": "string",
"description": "要回复的目标用户消息编号。",
},
"quote": {
"type": "boolean",
"description": "是否以引用回复的方式发送。",
"default": True,
},
"unknown_words": {
"type": "array",
"description": "回复前可能需要查询的黑话或词条列表。",
"items": {"type": "string"},
},
},
"required": ["msg_id"],
},
),
_build_tool_spec(
name="query_jargon",
brief_description="查询当前聊天上下文中的黑话或词条含义。",
parameters_schema={
"type": "object",
"properties": {
"words": {
"type": "array",
"description": "要查询的词条列表。",
"items": {"type": "string"},
},
},
"required": ["words"],
},
),
_build_tool_spec(
name="query_person_info",
brief_description="查询某个人的档案和相关记忆信息。",
parameters_schema={
"type": "object",
"properties": {
"person_name": {
"type": "string",
"description": "人物名称、昵称或用户 ID。",
},
"limit": {
"type": "integer",
"description": "最多返回多少条匹配记录。",
"default": 3,
},
},
"required": ["person_name"],
},
),
_build_tool_spec(
name="no_reply",
brief_description="本轮不发送可见回复,继续下一步思考。",
),
_build_tool_spec(
name="stop",
brief_description="暂停当前内部循环,等待新的外部消息。",
),
_build_tool_spec(
name="send_emoji",
brief_description="发送一个合适的表情包来辅助表达情绪。",
parameters_schema={
"type": "object",
"properties": {
"emotion": {
"type": "string",
"description": "希望表达的情绪,例如 happy、sad、angry 等。",
},
},
},
),
]
def get_builtin_tool_specs() -> List[ToolSpec]:
"""获取 Maisaka 内置工具声明。
Returns:
List[ToolSpec]: 内置工具声明列表。
"""
return create_builtin_tool_specs()
def get_builtin_tools() -> List[ToolDefinitionInput]:
"""获取兼容旧模型层的内置工具定义。
Returns:
List[ToolDefinitionInput]: 可直接传给模型层的工具定义。
"""
return [tool_spec.to_llm_definition() for tool_spec in create_builtin_tool_specs()]