脚本插件
适用于 AiVerse 1.0.2 及以上。
脚本插件让 AI 不止能用一个固定的工具集——你可以用 JavaScript 写一个插件,向 AI 注册自定义工具,并借助 ctx API 访问网络、文件、剪贴板、状态存储等宿主能力。装好后这些工具会自动出现在 AI 的工具列表里,像内置工具一样被调用。
入口在「设置 → 脚本插件」。
脚本能干什么
- 注册自定义工具:向 AI 增加可调用工具,AI 依据
description与parameters决定是否调用。 - 网络请求:
ctx.httpFetch,支持 method、自定义请求头与请求体——可对接任意 HTTP 接口。 - 文件读写:在插件自己的沙箱目录内读、写、删、列文件,防目录穿越。
- 状态与存储:
ctx.stateGet/stateSet(会话内内存)、ctx.storeGet/storeSet/storeRemove(持久化)。 - 剪贴板与通知:读写剪贴板、弹 Toast、发系统通知。
- 调用已有工具:
ctx.callTool调用 AiVerse 中自动授权的内置工具。 - 多插件隔离:每个插件独立 QuickJS 运行时,互不干扰。
怎么安装
插件打包成 zip:包内任意层级存在 plugin.json 即被识别。在「设置 → 脚本插件」点右上角「安装插件」,选择 zip 包。App 会解压到应用私有目录并解析清单。
- 无危险权限的插件安装后自动启用;
- 含危险权限的插件安装后不自动启用,卡片上的权限标签为橙色,确认后再手动打开开关。
启用后,插件注册的工具在下一条消息即可被 AI 调用,无需重启。
AI 如何调用
- App 常驻注册一个
plugins_list工具:AI 可先查看已装插件的介绍、声明的技能与 MCP server,再决定调用具体插件工具。 - 每个插件工具以
包名_工具名命名(如my_hello_greet),注册进统一工具注册表,与内置工具共用同一套授权机制。 - 插件清单里可声明
skills(推荐/依赖的技能)与mcpServers(依赖的 MCP 服务器),AI 据此判断是否需要配合技能或 MCP 完成任务。
与 MCP 搭配
插件可在 plugin.json 的 mcpServers 里声明依赖的 MCP 服务器名。MCP 负责把外部工具接进来(见 MCP 服务器),插件则可以经 ctx.callTool 调用自动授权的工具、把多个 MCP 工具编排成一个高层能力。
与提示词、技能搭配
插件可在 skills 里声明配套技能(见 技能);技能与插件都是可选的扩展层,AI 的行为边界与工作流由提示词约束(见 自定义提示词)。三者关系:提示词定义"怎么做事",技能沉淀"某类任务的标准流程",插件提供"可执行的新工具"。
目录结构与 plugin.json
一个插件是一个目录:
hello/
├── plugin.json # 清单(必需)
└── main.js # 工具入口(默认 main.js)
plugin.json 字段:
| 字段 | 必需 | 说明 |
|---|---|---|
package | ✅ | 唯一标识,建议反向域名(my.hello)。兼作工具命名前缀 |
name | ✅ | 显示名,出现在插件列表 |
version | 版本号 | |
description | 一句话说明 | |
author | 作者名 | |
main | 工具脚本,默认 main.js | |
api | 插件规范版本,默认 0.1.0 | |
permissions | 权限数组,不写 = 什么都不给 | |
skills | 配套技能名列表 | |
mcpServers | 依赖的 MCP 服务器名列表 | |
icon | 图标路径(预留) |
最小 plugin.json:
{
"package": "my.hello",
"name": "Hello 插件",
"version": "1.0.0",
"description": "我的第一个插件",
"main": "main.js",
"permissions": ["network"]
}
注册工具(main.js)
工具让 AI 能调用你的代码。把工具推进全局 $ptools 数组:
var $ptools = $ptools || [];
$ptools.push({
name: 'greet',
description: '向某人问好。', // AI 靠这句话决定要不要调
parameters: {
type: 'object',
properties: {
who: { type: 'string', description: '打招呼的对象' }
},
required: ['who']
},
handler: function (args) {
return JSON.stringify({ ok: true, message: '你好,' + args.who });
}
});
命名与 handler 约束
- 工具名会被拼成
包名_工具名(如my_hello_greet),同一个插件的所有工具共用同一包名前缀,卸载时按前缀整体撤销。 handler参数是工具参数的 JSON 对象;返回值应为字符串(通常JSON.stringify(...)),会被序列化后交给 AI。handler是同步调用;抛出的异常由宿主捕获并作为错误返回。- 可选
permission字段:为单个工具声明所需权限。
ctx API 与权限
ctx 是宿主注入到插件 JS 里的能力桥,ctx.xxx() 直接调用。所有能力受 plugin.json 的 permissions 控制,不声明即不可用;危险权限安装时需用户确认。
| 方法 | 说明 | 需要的权限 |
|---|---|---|
ctx.showToast(msg) | 弹短提示 | — |
ctx.notify(title, body) | 发通知 | notify |
ctx.getEnv(key) / ctx.setEnv(key, value) | 会话级环境变量 | — |
ctx.stateGet(key) / ctx.stateSet(key, value) | 会话级状态(内存) | — |
ctx.storeGet(key) / ctx.storeSet(key, value) / ctx.storeRemove(key) | 持久化存储(store.properties) | — |
ctx.httpFetch(url, optionsJson) | HTTP 请求,返回 {status, body};optionsJson 可含 method/headers/body | network |
ctx.fileRead(path) / ctx.fileList(path) | 读沙箱文件 / 列目录 | file |
ctx.fileWrite(path, content) / ctx.fileDelete(path) | 写 / 删沙箱文件 | file:write |
ctx.clipboardGet() / ctx.clipboardSet(text) | 读写剪贴板 | clipboard |
ctx.callTool(name, argsJson) | 调用 AiVerse 里自动授权的工具 | — |
权限标识:network、file、file:write、clipboard、notify(server 为预留)。危险权限为 network、file:write、clipboard,安装时橙色提示。
文件沙箱
fileRead / fileWrite / fileDelete / fileList 只能访问插件自己的目录,用相对路径;传绝对路径或 .. 会被拒绝。
网络请求示例
$ptools.push({
name: 'fetch_json',
description: '请求一个 JSON 接口并返回。',
parameters: {
type: 'object',
properties: { url: { type: 'string', description: '接口地址' } },
required: ['url']
},
handler: function (args) {
var res = ctx.httpFetch(args.url, JSON.stringify({ method: 'GET' }));
var parsed = JSON.parse(res);
if (parsed.status !== 200) {
return JSON.stringify({ ok: false, error: 'HTTP ' + parsed.status });
}
return parsed.body;
}
});
打包、安装与调试
- 打包:把含有
plugin.json的目录压成 zip(cd hello && zip -r ../hello.zip . -x '.*'),包内任意层级含plugin.json即可。 - 安装:设置 → 脚本插件 → 右上角「安装插件」→ 选 zip。
- 启用/禁用:卡片右侧开关,切换即时生效(注册/注销工具)。
- 卸载:卡片上的「卸载」,会删除插件文件,不可恢复。
- 调试:日志可在「日志」页查看;插件加载与调用失败会记录到日志。
常见问题
- 工具没出现 / 调不到:确认插件已启用;工具名是否以包名为前缀;
$ptools是否在main.js顶层正确 push。 - 报「缺少权限」:
ctx.xxx需要的权限未在plugin.json的permissions里声明,或安装时用户没确认危险权限。 - 调用报错:
handler里抛了异常,或返回了非字符串;把错误JSON.stringify后返回更利于排查。 - 路径越界:文件操作只能用插件沙箱内的相对路径。
完整示例
{
"package": "demo.tool",
"name": "示例插件",
"version": "1.0.0",
"description": "演示注册工具与网络能力",
"main": "main.js",
"permissions": ["network", "notify"]
}
var $ptools = $ptools || [];
$ptools.push({
name: 'ping',
description: '测试插件是否已加载。',
parameters: { type: 'object', properties: {}, required: [] },
handler: function () {
ctx.showToast('插件已响应');
return JSON.stringify({ ok: true, pong: true });
}
});
把上述两文件放进 demo.tool/ 目录,压成 zip,在「设置 → 脚本插件」安装并启用,即可在对话中让 AI 调用 demo_tool_ping。