言栖插件开发文档

一个插件就是一个 JSON:HTML + CSS + JS,运行在受限沙箱里。

快速开始

入口:在言栖里打开 我 → 发现 → 插件中心。你可以:

  1. 运行官方示例:专注计时、帮我决定、待办清单,点卡片直接运行。
  2. 新建插件:填写名称、ID、HTML、CSS、JS,点「预览」立即看效果,保存后进入「我的插件」。
  3. AI 生成:先选软件插件或角色插件,再用一句话描述需求;服务端调用内置模型生成初版,按实际 Token 用量扣 AI 积分。
  4. 导入 / 导出:插件是 JSON,可以复制给别人导入,也可以从官方示例复制一份再改。

插件保存在当前账号的浏览器 localStorage 里,不会上传到服务器;清除浏览器数据或换设备不会自动同步。

插件格式

插件是一个 JSON 对象,字段如下:

id必填。小写字母开头,2~40 位,只能包含 a-z、0-9、-。同时作为本地存储和分享标识。
kindsoftware(软件插件,在插件中心运行)或 character(角色插件,挂到角色聊天)。不填按 software 处理。
name必填。插件名称,最多 30 字。
desc一句话说明,最多 180 字。
version版本号,例如 1.0.0;不合法时回退为 1.0.0。
category分类,最多 16 字,例如「效率」「生活」「工具」。
icon图标名,例如 sparkle、box、pen、star、robot;不认识时回退为 sparkle。
prompt角色插件专用。启用后把这段指令注入角色的系统提示词,最多 8000 字。
permissions软件插件权限数组,只能从 storage、toast、user、clipboard 中选。
html只放 body 内部结构。禁止 <script>、<style>、<iframe>、<link>、<meta>、<object>、<embed>。
css内联样式,最多 16KB。
js内联脚本,最多 24KB;HTML + CSS + JS 总大小不超过 48KB。
插件 ID 不能和官方示例冲突;保存时如果 ID 已存在,会提示是否覆盖。AI 生成或导入时 ID 冲突会自动加后缀。

角色插件

新建插件时把「插件类型」选成「角色插件」,在「角色指令」里写清楚它要在聊天中怎么表现。保存后打开任意角色的「编辑角色」,开启「启用角色插件」,勾选这个插件并保存;之后这个角色聊天时就会带上这段指令。

角色插件没有界面,也不需要 HTML/CSS/JS;它只影响角色说话方式或行为。多个角色插件可以同时启用,指令会按顺序拼接后注入系统提示词。

宿主 API

插件在 sandbox="allow-scripts" 的 iframe 里运行,和主应用不同源。唯一可用的桥是全局 YX,除 ready 外都返回 Promise。

YX.ready(fn)DOM 就绪后执行 fn,最常用的入口。
YX.user()返回 { id, name },需要 user 权限;不会返回邮箱、手机号或 Token。
YX.toast(text)显示宿主提示,最多 200 字,需要 toast 权限。
YX.storage.get(key)读取当前账号下本插件的数据,需要 storage 权限;没有时返回 null。
YX.storage.set(key, value)写入 JSON 可序列化数据,单插件总容量 128KB。
YX.storage.remove(key)删除一个键。
YX.copy(text)复制到剪贴板,需要 clipboard 权限,最多 5000 字。
YX.close()关闭插件,回到插件中心。

最小示例

<!-- HTML -->
<div class="box">
  <h2 id="count">0</h2>
  <button id="add">点一下</button>
</div>

/* CSS */
.box{padding:28px 18px;text-align:center}
.box h2{font-size:52px;margin:0 0 18px;color:#eef2ff}
.box button{border:0;border-radius:12px;padding:10px 22px;background:#3ddc84;color:#062016;font-weight:600}

// JavaScript
YX.ready(function () {
  var n = 0;
  var el = document.getElementById('count');
  YX.storage.get('count').then(function (v) { n = Number(v) || 0; el.textContent = n; });
  document.getElementById('add').onclick = function () {
    n++;
    el.textContent = n;
    YX.storage.set('count', n).then(function () { YX.toast('已保存'); });
  };
});
数据按「账号 + 插件 ID + key」隔离。同一个插件在不同账号下看不到彼此的数据。

限制与安全

插件是用户自己写的代码,平台按「不信任」处理:

插件运行结果由插件作者负责。安装来源不明的插件前,先点「预览」或检查代码;发现异常可在「工单中心 / 在线客服」反馈。

AI 生成插件

入口:插件中心 → AI 生成。先选「插件类型」,再描述你想要的效果,服务端会调用后台配置的 内置模型 生成初版。

生成软件插件

做一个喝水提醒:顶部显示今天喝了几杯,点「喝一杯」加一,
数据保存在本地;到 8 杯时提示今天达标;再提供「重置」按钮。
界面要适合手机,深色玻璃风格,不要外部图片。

建议写清楚:界面元素、操作、数据是否保存、空状态和错误提示。描述越具体,生成结果越接近可用。

生成角色插件

让角色在聊天里提醒我按时吃饭:到饭点用自然的话提醒,
不要连续追问;我加班时提醒我别硬撑,晚上提醒早点休息。

角色插件只生成一段注入角色系统提示词的指令,不生成界面。建议写清楚:触发时机、具体行为、语气、频率上限、什么时候停止。保存后打开「编辑角色 → 启用角色插件」,勾选它才会生效。

完整示例

下面是一个可直接保存的最小插件 JSON:

{
  "id": "my-timer",
  "name": "我的计时器",
  "version": "1.0.0",
  "desc": "一个最小插件示例",
  "category": "工具",
  "icon": "sparkle",
  "permissions": ["storage", "toast"],
  "html": "<div class=\"box\"><h2 id=\"t\">00:00</h2><button id=\"go\">开始</button></div>",
  "css": ".box{padding:24px;text-align:center}.box h2{font-size:44px;margin:0 0 18px}.box button{border:0;border-radius:12px;padding:10px 22px;background:#3ddc84;color:#062016;font-weight:600}",
  "js": "var s=0,id=null;YX.ready(function(){function show(){var m=Math.floor(s/60),x=s%60;document.getElementById('t').textContent=(m<10?'0':'')+m+':'+(x<10?'0':'')+x;}document.getElementById('go').onclick=function(){if(id){clearInterval(id);id=null;this.textContent='继续';}else{id=setInterval(function(){s++;show();},1000);this.textContent='暂停';}};show();});"
}

保存后点卡片即可运行;也可以导出 JSON,粘贴到另一台设备的「插件中心 → 导入」。

常见问题

为什么插件里 fetch 不工作?

沙箱按安全策略禁止网络请求。需要数据时请让用户手动输入,或用插件自己的本地存储。确实需要联网的能力,应做成平台内置功能。

为什么 localStorage 是空的?

插件不能直接访问 localStorage,必须用 YX.storage.get / set,并在 permissions 里声明 storage。数据按账号隔离,换账号会看不到。

为什么换了设备插件没了?

插件和插件数据只在本机浏览器里,不参与聊天记录备份。请用「导出 JSON」保存代码,换设备后「导入」。

AI 生成失败会扣钱吗?

不会。只有成功生成才按实际 Token 扣费;失败不扣费。如果页面显示已扣费但没有生成结果,请在「工单中心」提供时间和模型名。

可以发布到插件广场给别人用吗?

当前版本插件保存在本机账号下,通过导出 JSON 分享;还没有公开上架 / 审核流程。后续开放时会在插件中心里通知。

← 返回言栖