Skip to content

插件系统

插件系统允许第三方扩展 CocoCat 的功能——注册新工具、挂接到工具调用生命周期、无需修改核心代码。

架构

plugins/{name}/
├── plugin.json      # 清单(必选)
├── *.py             # 处理器代码
└── ...              # 其他资源

所有插件存放在项目根目录 plugins/ 下,每个子目录一个插件。

发现机制

plugin_manager.py 提供两级发现:

方式说明
目录扫描扫描 plugins/*/plugin.json,按 manifest 加载
entry_points(预留)支持通过 Python entry_points 注册

调用 discover_plugins() 返回 {name: manifest} 字典。

Manifest 格式 (plugin.json)

json
{
  "name": "my-plugin",
  "version": "1.0.0",
  "description": "示例插件",
  "tools": [
    {
      "name": "my_tool",
      "description": "工具描述",
      "inputSchema": {
        "type": "object",
        "properties": {
          "param1": {"type": "string"}
        },
        "required": ["param1"]
      },
      "handler": "handler.py:my_func"
    }
  ],
  "hooks": {
    "pre_tool_call": ["hooks.py:pre_tool"],
    "post_tool_call": ["hooks.py:post_tool"]
  }
}

工具注册

tool_registry.py 定义 PluginTool 基类,继承自 Tool

python
class PluginTool(Tool):
    def execute(self, **kwargs) -> str:
        result = self._handler(**kwargs)
        return str(result) if result is not None else ""

load_plugin_tools(manifest) 根据 manifest 中的 tools 数组动态创建 PluginTool 实例,handler 引用格式为 file.py:function_name

钩子系统

plugin_hooks.py 提供 HookRegistry 类:

事件触发时机可做操作
pre_tool_call工具执行前拦截/修改参数、拒绝执行
post_tool_call工具执行后修改/记录结果

pre_tool_call

python
def pre_tool(tool_name: str, args: dict, ctx: dict) -> dict:
    if tool_name == "exec_command" and "rm" in args.get("command", ""):
        return {"action": "deny", "reason": "rm blocked by plugin"}
    return {"action": "continue", "args": args}

返回值说明:

  • action: "continue" — 放行,可选 args 修改参数
  • action: "deny" — 拒绝,附带 reason

post_tool_call

python
def post_tool(tool_name: str, args: dict, result: str, ctx: dict) -> dict:
    return {"result": result + "\n[audited by plugin]"}

安装

install_plugin(source, name="") 支持两种来源:

source 格式行为
./path/to/plugin本地路径复制到 plugins/{name}
https://github.com/...git clone --depth 1plugins/{name}

安装后自动验证 plugin.json 是否存在。

卸载

uninstall_plugin(name) 删除 plugins/{name} 目录。

完整示例

plugins/example-plugin/
├── plugin.json
├── tools.py          # 工具处理器
└── hooks.py          # 钩子处理器
json
{
  "name": "example-plugin",
  "version": "1.0.0",
  "description": "示例:添加 echo 工具并在执行前记录",
  "tools": [
    {
      "name": "echo",
      "description": "回显输入",
      "inputSchema": {
        "type": "object",
        "properties": {
          "text": {"type": "string"}
        },
        "required": ["text"]
      },
      "handler": "tools.py:echo_handler"
    }
  ],
  "hooks": {
    "pre_tool_call": ["hooks.py:audit_pre"]
  }
}

基于 MIT 协议开源