小组件
编写可嵌入到深度模式里的辅助小组件
什么是小组件
小组件是一种特殊的沉浸创作模式:它可以嵌入到某个深度模式的游戏(下面称之为主线)里运行。
典型用途:
- 群聊
- 私聊
- 热搜
- ...
一句话理解边界:
- 共享主线(读写都作用在主线那一份):角色、物品、关系、世界、玩家、永久记忆、人设。小组件改了它们,等于改了主游戏。
- 小组件私有沙盒(主线和其他小组件都看不到):
剧情设定、场景设定、自定义(custom)属性、存档。 - 消息比较特殊:所有 topic 的消息存在同一张表里,但按
topic隔离——小组件默认只读到自己 topic 的消息,需要时可显式去读主线(见下文「读取消息历史」)。
「共享」意味着没有回收站:小组件里创建 / 修改 / 删除角色、编辑人设,都是直接写主线,会立刻影响主游戏,且不会自动回滚。真正私有、互不干扰的只有 custom 属性和存档。
创作流程
- 在创作台「创作模式」面板选择「沉浸创作」
- 勾选「可作为小组件」开关
- 你可以编辑的区块:
- 世界观及剧情设定:小组件本身的 LLM 设定(人设、行为规则、回复风格等)
- 场景设定:小组件自己的场景设定,类似于沉浸模式(不同场景下不同行为)
- 自定义属性:小组件的私有沙盒字段
- 封面、标题、标签、简介、开幕小剧场等基础信息
小组件能做什么
| 资源 | 归属 | 能读 | 能写 |
|---|---|---|---|
| 消息 | 同表、按 topic 隔离 | 默认仅自己 topic;显式传 storvia_chat_main 可读主线 | 写入自己 topic |
| 永久记忆 | 共享主线 | ✅ | ✅ 与主线走同一条生成链,同等待遇 |
| 人设 | 共享主线 | ✅ | ✅ 写回主线(会改动主游戏) |
| 角色 / 物品 / 关系 / 世界 / 玩家 | 共享主线 | ✅ | ✅ AI 自动更新,写回主线 |
自定义(custom) 属性 | 小组件私有沙盒 | ✅ | ✅ 落自己沙盒,主线 / 其他组件都看不到 |
关键点:
- 共享主线的属性(角色 / 物品 / 关系 / 世界 / 玩家 / 记忆 / 人设)用的都是主线那一份,小组件里读到的、写回去的都是主线的数据——小组件不能为它们另起一套平行 schema(创作台发布时会自动剔除)。
custom属性是小组件独有的私有沙盒:只有该小组件自己运行时才会注入进 LLM,主线和其他小组件既读不到、也无法覆盖。- AI 自动更新指:LLM 生成的正文里夹带的结构化状态变更,会被系统自动解析并落库——共享属性写回主线,
custom写回自己的沙盒。 - 深度模式主线本身没有
custom(custom 是自由模式专属),所以在深度模式下,custom就是纯粹属于小组件的字段。
沙盒数据
每次小组件被安装到某主线对话,会给你的小组件开一份私有沙盒,物理位置在 conversations.metadata.widget_sandbox[你的 game_id]。沙盒里存三样东西:
custom:自定义属性的当前值custom_inject:各 custom 字段是否注入进 LLM 的开关save_data:小组件的存档数据
沙盒的生命周期:
- 用户卸载小组件:沙盒数据保留(重新安装即恢复,不会丢失数据,也不会自动清理数据)
- 多次安装同一小组件:使用同一份沙盒
- 沙盒按
game_id隔离:主线看不到它,其他小组件也各有各的沙盒,互不可见
Topic 命名约定
小组件通过 SDK 调用聊天能力时必须传一个 topic,让自己的消息流与主线(storvia_chat_main)以及其他小组件区分开。
强制格式:<游戏 id>:<组件内部 topic>
- 前缀 = 游戏 id(
game_id),即你这个小组件被发布后由平台分配的唯一标识。平台保证全局唯一,永远不会与别人的小组件撞。- 还没发布拿不到 id?可以先把小组件以私有可见性发布一次,发布成功后即可在游戏详情页拿到
game_id,再回来填到 topic 里使用
- 还没发布拿不到 id?可以先把小组件以私有可见性发布一次,发布成功后即可在游戏详情页拿到
- 后缀 = 你小组件内部自己用的 topic 名(自由命名,用来区分自己内部的多条对话流,如不同房间、不同会话)
// 推荐:用 game_id 作为前缀
const topic = `${gameId}:main`; // 组件主聊天流
const topic = `${gameId}:room-${roomId}`; // 多房间场景
const topic = `${gameId}:user-${userId}`; // 多对一私聊
// 不推荐
const topic = "chat"; // 没前缀,必撞主线 / 其他组件
const topic = "widget:chat"; // 前缀不带游戏 id,多个小组件同名会撞平台不会强制校验 topic 格式,但不按这个规范走,发生跨组件消息污染时责任自负。
读取消息历史(自己 / 主线 / 全部)
小组件通过 chat.messages({ topic, ... }) 拉消息时,topic 参数决定看到的范围:
| 传值 | 拿到的范围 | 典型用途 |
|---|---|---|
${gameId}:xxx(自己的 topic) | 仅自己这个 topic 的消息 | 小组件正常聊天 / 翻看历史 |
"storvia_chat_main" | 主线对话的消息 | 想让小组件「读懂主角现在在干嘛」 |
| 其他小组件的 topic | 该组件的消息 | 一般用不到,不建议跨组件读 |
不传 / null | 当前会话下所有 topic 的消息(主线 + 全部组件) | 极少需要;通常是 bug |
// 小组件自己的对话历史
await sdk.chat.messages({ topic: `${gameId}:main`, order: 'asc', limit: 20 });
// 主线对话历史(让群聊 / 私聊 widget 知道主角刚发生了什么)
await sdk.chat.messages({
topic: 'storvia_chat_main',
order: 'desc',
limit: 10,
});
// 全部消息(不传 topic)—— 几乎用不到,注意会拿到所有 widget 的消息流
await sdk.chat.messages({ order: 'desc', limit: 20 });不传 topic 会把当前 conversation 下所有 topic 的消息混在一起返回(主线 + 你自己 + 其他小组件)。除非确实需要"全景视角",否则永远显式传 topic,避免拿到不该读的内容、上下文错乱。
SDK 调用
聊天、属性(创建、修改、删除)、玩家人设编辑、角色人设(创建、修改、删除)等功能和沉浸模式完全一样调用 SDK 即可。读写 custom 属性会自动落到你自己的沙盒,不需要做任何额外处理。
注意区分写入落点:只有 custom 属性写进小组件私有沙盒。角色、物品、关系、世界、玩家、人设的读写全部作用在主线——在小组件里通过 SDK 建角色 / 改人设 / 删物品,改的是主游戏本身,不是组件私有副本,务必谨慎。
共享设置
以下设置不属于小组件,跟着当前主线对话走:
- 模型选择
- 温度
- 回复长度
- 回复语言