外置声明式插件
只需一个 plugin.json,适合增加聊天动作、生成规则、临时 NPC、插件存储和受限网络请求。
先选对扩展方式
只需一个 plugin.json,适合增加聊天动作、生成规则、临时 NPC、插件存储和受限网络请求。
需要新宿主能力或复杂业务编排时,在 kmp/plugins-api 实现稳定契约,并随应用一起发布。
应用可以检查和保存旧包,但不会执行其中的 Python 或其它任意代码。
请迁移到声明式插件五分钟快速开始
新建目录 my-quick-reply/,在里面放置以下 plugin.json。这个插件会读取当前聊天上下文,调用用户已经配置的模型,并把结果作为可编辑草稿返回。
{
"id": "example-quick-reply",
"name": "快捷接话",
"version": "0.1.0",
"apiVersion": "2",
"description": "结合当前场景生成一句可编辑的回复草稿。",
"defaultEnabled": false,
"permissions": [
"chat.context.read",
"chat.draft.write",
"model.invoke"
],
"settings": [
{
"key": "tone",
"title": "语气",
"type": "enum",
"default": "克制",
"options": ["克制", "温柔", "直接"]
}
],
"contributes": {
"chatActions": [
{
"id": "quick-reply",
"title": "快捷接话",
"placement": "composer",
"icon": "sparkles"
}
]
},
"execution": {
"mode": "declarative",
"chatActions": {
"quick-reply": {
"operation": "suggest",
"direction": "结合当前场景生成下一句。语气:{{config.tone}}。草稿:{{seed_text}}"
}
}
}
}
ZIP 根目录或 ZIP 内第一层目录必须包含 plugin.json。
打开“设置 → 插件”,选择 ZIP;确认名称、API 版本和权限。
安装后插件默认保持关闭。手动启用,再进入聊天的插件菜单。
生成结果只写入草稿,由用户确认后发送。
清单格式
| 字段 | 是否必填 | 说明 |
|---|---|---|
id | 是 | 稳定且唯一;只能包含字母、数字、下划线和连字符,例如 acme-quick-reply。 |
name | 是 | 插件管理和聊天菜单中显示的名称。 |
version | 建议 | 插件版本,例如 0.1.0。 |
apiVersion | 建议 | 新插件写 2;当前宿主兼容 1/2,缺省按 1 处理。 |
description | 否 | 解释用途、数据范围和用户可见效果。 |
defaultEnabled | 否 | 第三方包安装后仍保持关闭,需用户显式启用。 |
permissions | 按能力 | 最小权限集合;缺少所需权限的配方不会进入可执行态。 |
settings | 否 | 由宿主渲染的 boolean、integer 或 enum 设置。 |
contributes | 是 | 向 UI 声明动作、生成增强器或临时 NPC 生成器。 |
execution | 是 | mode 必须为 declarative,并为每个贡献点提供同 ID 配方。 |
贡献与执行必须成对。 在 contributes.chatActions 声明了 quick-reply,就必须在 execution.chatActions.quick-reply 提供配方;ID 不一致会使插件不可执行。
模板与设置
{{seed_text}}当前输入框里的草稿{{direction}}动作调用时附带的方向{{config.tone}}插件设置中的 tone{{storage.notes}}插件独立数据区的 notes
设置值由宿主保存到插件自己的配置区,并通过 {{config.<key>}} 注入模板。不要把 API Key 或长期密钥放入普通设置;当前外置插件没有密钥保险箱能力。
贡献点
显示在聊天输入区插件菜单中。适合生成草稿、候选回复、存取插件数据、网络查询和角色控制。
按会话开关,把规则注入后续主对话生成。关闭或停用插件后,宿主会清除残留规则。
结合当前场景生成临时角色,并由宿主安全写入当前会话的参与者与入场消息。
当玩法涉及关键词、回合数、概率或会话状态时,把规则放进 execution.rules。同一插件可包含多条规则,每条规则也可串联多个动作;状态只属于当前会话。
"permissions": ["chat.context.read", "generation.enhance", "model.invoke", "chat.state.write"],
"execution": {
"mode": "declarative",
"rules": [
{
"id": "merchant-arrives",
"title": "神秘商人登场",
"event": "before_generation",
"match": {"everyTurns": 5, "chancePercent": 30},
"actions": [
{"type": "add_instruction", "instruction": "让一名神秘商人自然进入场景。"}
]
},
{
"id": "remember-refusal",
"title": "记录拒绝",
"event": "after_turn",
"match": {"keywords": ["拒绝", "不买"]},
"actions": [
{"type": "increment_state", "key": "refusals", "amount": 1}
]
}
]
}
规则仍由 Kotlin 宿主解释执行。生成前规则可追加本轮指令;回合结束规则可设置或增减状态。同一回合重试不会重复累计,插件也不能借此运行脚本或访问任意文件。
"permissions": ["chat.context.read", "generation.enhance", "model.invoke"],
"contributes": {
"generationEnhancers": [
{"id": "short-lines", "title": "短句模式", "icon": "short_text"}
]
},
"execution": {
"mode": "declarative",
"generationEnhancers": {
"short-lines": {
"rule": "每名角色每次最多说两句,保留自然停顿,不要压缩关键信息。"
}
}
}
"permissions": ["chat.context.read", "chat.cast.write", "model.invoke"],
"contributes": {
"temporaryNpcGenerators": [
{"id": "visitor", "title": "引入来客", "icon": "person_add"}
]
},
"execution": {
"mode": "declarative",
"temporaryNpcGenerators": {
"visitor": {
"direction": "生成一名与当前冲突有关、动机明确但不过度抢戏的来客。",
"notice": "一名新人物进入了场景。"
}
}
}
聊天动作操作
| operation | 关键字段 | 主要权限 | 结果 |
|---|---|---|---|
suggest | direction | 上下文、草稿、模型 | 一段建议草稿 |
variants | direction | 上下文、草稿、模型 | 多个候选回复 |
storage_get | key | storage.read | 读取插件文本数据 |
storage_set | key、value | storage.write | 写入插件文本数据 |
http_get | url、headers | network.access | 响应文本写入草稿 |
http_post | 加 body | network.access | 响应文本写入草稿 |
reply_as_character | direction | 人物、上下文、草稿、模型 | 选择角色并生成草稿 |
mute_character | character | chat.cast.write | 当前会话角色禁言 |
unmute_character | character | chat.cast.write | 解除角色禁言 |
未知操作、空的必填字段、缺失权限或未在清单中声明的 action ID 都会被宿主拒绝。
权限模型
权限不是装饰字段。 安装时用户必须确认权限,运行时宿主会再次核对插件启用状态、贡献点 ID 和所需权限。不要为了“以后可能用到”申请额外能力。
打包、安装与调试
Compress-Archive -Path .\my-quick-reply\* -DestinationPath .\my-quick-reply.zip
(cd my-quick-reply && zip -r ../my-quick-reply.zip .)
.. 路径穿越或符号链接。execution.mode、API 版本、权限和贡献点配方是否完整。安全边界
外置 ZIP 中的 Python、JAR、原生库和脚本不会被加载。
数据键只能使用安全标识符,不能逃逸插件自己的目录。
仅 HTTPS;拒绝显式本地和私有地址、用户凭据 URL、重定向与危险请求头;30 秒超时,响应上限 1 MiB。
插件只能请求宿主执行指定模型任务,不能读取用户 API Key。
角色和 NPC 变更由宿主校验并原子写入,插件不能直接操作 Room 或会话文件。
执行端点会检查启用态,禁用时同时移除会话中的生成增强规则。
发布前
ID 与版本稳定插件 ID 使用独特、可识别的安全标识,升级只变更 version。
API 明确新插件写 "apiVersion": "2"。
最小权限逐个对照操作表,不申请配方未使用的权限。
ID 全部对齐contributes 中每个 ID 都有同名 execution 配方。
失败可读为可能返回空结果的动作设置清楚的 empty_notice。
真机验证完成检查、安装、启用、执行、禁用、升级和卸载完整流程。