插件能用什么
插件启用时拿到一个 context:它只带这个插件被允许用的那几样接口。能力分三层——这台机器允许什么、插件要什么、装的人确认了什么——三层都放行才拿得到。
本页 5 节
三层
- 这台机器允许插件申请哪些:人格配置
[plugins].allowed_capabilities(3.21)。上限之外的,插件写了也启用不了。 - 插件要哪些:
plugin.json的permissions、optional_permissions(3.8)。 - 装的人确认了哪些:必需的装时一次确认,可选的在插件设置里一项一项开。确认记录在宿主自己的目录里(
data/plugin_host/grants.json),不在插件能写的地方。插件更新后要了新的必需能力,旧的确认作废。
context 上有什么
context.has(能力)、context.require(能力):查、要一项能力(没有就抛PermissionError)。context.register_action(名字, 处理函数):登记一个人格能用的动作(要register_action;名字必须是插件编号.动作名)。context.register_webui_page({"title": …, "path": …}):加一个网页后台的页面(要register_webui_page)。context.storage_dir():插件自己的数据目录data/plugin_data/<插件编号>/,更新插件不动它,备份带着它(要storage.private)。context.config():装的人在插件设置里保存的配置(只读)。context.spawn(名字, 工厂函数):一个由宿主托管的后台任务:崩了按退避重启,停用、重载时一起停(3.12)。context.host_info()、context.release_info():宿主的版本信息;发布来源和公钥(要release.read)。context.discord、context.qq:两个平台的接口,只在声明了相应能力时有(3.10)。context.knowledge:往宿主人格所在服务器的知识库写这个插件自己的公开条目(要knowledge.public_write;每个插件每个服务器有条数和字数上限,读不到别的知识和记忆)。context.services:旧插件用的几样服务(比如只读最近聊天的store),按能力给。
能力表
- 基础:
read_messages(收到before_message/after_generation钩子)、modify_messages(改写别人发的消息,默认上限里没有)、modify_decision(改这一轮的决定)、call_model(拿模型客户端,默认上限里没有)、register_action、register_webui_page。 - Discord:
discord.interactions、discord.dm.send、discord.dm.session、discord.channel.send、discord.message.delete、discord.commands.legacy、discord.mention.everyone。 - QQ:
qq.commands、qq.private.session、qq.private.send、qq.group.send。 - 其他:
storage.private、release.read、webui.plugin_panel、knowledge.public_write。
每一项宿主怎么守(限流、只能删自己发的、会话最长多久……)写在仓库的 docs/PLUGIN_PERMISSIONS.md。
钩子
入口对象上实现了这几个方法的,宿主在对应的时候调用:
before_message、after_generation:要read_messages,看到每条消息、每条生成的回复;before_message的返回值要替换原消息,还得有modify_messages。before_generation_plan:要modify_decision。规划完、生成回复之前调,传进来的是这一轮的回复计划;返回一个新的回复计划就用它。插件没写这个方法、写了after_decision的,after_decision在同一个时候被调(旧名字)。
只发这几个;不在表里的钩子名,宿主一律不发(名单和要的能力:src/aeria/plugins.py 的 HOOK_PERMISSIONS;改回复计划那一个走 invoke_generation_plan)。每个钩子最多等 2 秒([plugins].hook_timeout_seconds),超时当没回;钩子里抛错只记日志,不影响人格。
没做到的
- 读写记忆、关系、人格设定、密钥的接口,默认上限里都没有,也还没有设计成能安全开放的样子。
- 钩子对所有人格、所有服务器都发:一个插件不能只对某个服务器挂钩子,要自己在钩子里判断。