属性
SDK 的状态模块 —— 世界、玩家、角色、关系、物品、扩展属性、存档,以及完整状态读取
SDK 提供 7 个分模块 + 1 个全量读取接口(storvia.state),用于读写游戏中的各种数据。前 5 个模块的数据会自动注入 AI 提示词,AI 每轮回复时也会自动更新。custom 默认不注入 AI,可通过创作台开启「AI 追踪」选择性注入。save 完全独立、永不注入 AI,专供游戏运行状态持久化。
| 模块 | AI 感知 | 数据结构 |
|---|---|---|
storvia.world | 自动注入 | 扁平 KV 对象 |
storvia.player.state | 自动注入 | 按分组的 KV |
storvia.characters.state | 自动注入 | 角色名 → 按分组的 KV |
storvia.relationships | 自动注入 | 关系数组 |
storvia.inventory | 自动注入 | 分组 → 物品 Record(上限 100 件) |
storvia.custom | 可选注入 | 文本/数值(可分组,上限 100 字段) |
storvia.save | 永不注入 | 任意 JSON(独立配额,≤ 256KB) |
storvia.memory | 自动注入 | AI 记忆文本 |
storvia.state | — | 一次性返回上述所有模块的合并快照 |
前 5 个模块的字段定义需要在创作台中配置(和深度创作一样),配置方法参考 深度创作。这里介绍的是如何通过 SDK 在游戏代码中读写数据。
角色数量上限:每个会话最多 10 个角色处于活跃状态、可被 AI 看到。当超过上限时,系统会按 priority 从低到高把多余角色移入休眠区(dormant)。休眠的角色不再注入 AI 提示词、AI 也不会更新它们的属性,但数据仍保留。可以通过 storvia.characters.setPriority() 调整排序,让某个角色重新进入活跃区。
storvia.world — 世界状态
存储全局环境信息。世界状态只有以下 5 个固定字段,由创作台按需启用,不支持自定义字段:
| 字段 | 说明 |
|---|---|
time | 时间(如"晚上 21:00") |
date | 日期(如"2024年3月15日") |
location | 地点(如"秦照野的直播间") |
region | 地区(如"江南水乡") |
weather | 天气(如"小雨") |
get() 返回当前存储的世界状态,update() 只接受上表中的 5 个字段,传入其他字段名会报错。
world.get()
获取当前世界状态。
const world = await storvia.world.get();
// { time: "晚上 21:00", location: "秦照野的直播间" }world.update(data)
更新世界状态。传入的字段会与已有数据合并,未传入的字段保持不变。只传已启用的字段,传入未启用字段会被忽略。
await storvia.world.update({
time: "深夜 23:30",
location: "回到家中",
});storvia.player — 玩家
player.get()
获取玩家基本信息(名称、性别、描述、头像)。
const player = await storvia.player.get();
// { name: "小明", gender: "male", description: "冒险者", avatar: "https://..." }player.update(data)
更新用户人设。传入字段会合并到现有数据,未传入的字段保持不变。name + description 合计上限 5000 字符。
await storvia.player.update({
name: "小明",
gender: "male",
description: "22岁的新晋制作人",
avatar: "https://example.com/player.png", // 可选
});player.state.get()
获取玩家状态。不传参数返回全部分组,传分组名返回该组数据。
字段值为 RichFieldValue 对象,包含 value(当前值)、type(字段类型)以及可选的 min/max(数值范围)。可使用 SDK 导出的 extractFieldValue() 工具函数提取原始值。
作者在创作台配置初始属性值时,可以留空不填。留空的字段在游戏开局不会出现在
state 里,聊天页面也不会显示。等到 AI 在对话中首次赋值(或 SDK 调用
player.state.update())后才会开始展示。这种"渐进式揭示"适合做好感度、剧情开关等属性。
import { extractFieldValue } from "@storvia/sdk";
// 获取全部分组
const allState = await storvia.player.state.get();
// {
// "经济": {
// "花园币": { value: 500, type: "number", min: 0, max: 99999 },
// "等级": { value: 3, type: "number", min: 1, max: 100 }
// },
// "数据": {
// "粉丝": { value: 120, type: "number" }
// }
// }
// 提取原始值
const coins = extractFieldValue(allState["经济"]["花园币"]); // 500
// 获取特定分组
const economy = await storvia.player.state.get("经济");player.state.update(group, values)
更新指定分组的玩家状态。传入的字段与该组已有数据合并。只需传简单值,系统会自动保留字段的元数据(type/min/max)并做范围钳位。
await storvia.player.state.update("经济", {
花园币: 450, // 扣了 50 币,系统自动钳位到 [0, 99999]
经验: 180, // 加了 30 经验
});分组名和字段名必须和创作台中配置的完全一致(包括中英文、空格等)。
storvia.characters — 角色
characters.list()
获取所有角色列表。预设角色的 description 为作者设定(对玩家可见),用户可通过 userDescription 补充。创作台里为预设角色上传的头像会随 avatar 字段返回完整可访问的 URL。
const chars = await storvia.characters.list();
// [{
// name: "秦照野", // 角色名
// avatar: "https://...", // 头像
// description: "", // 预设角色固定为空字符串(作者人设仅 AI 可见);自建角色为用户撰写
// introduction: "对外介绍文本", // 仅预设角色有意义,作者资产,SDK 只读
// visibleAtStart: true, // 开局是否出场,仅预设角色有意义,作者资产,SDK 只读
// userDescription: "对我温柔一些", // 用户补充人设
// gender: "male", // "male" | "female" | "other";老数据可能没有
// isPreset: true // 是否为作者预设角色
// }, ...]characters.get(name)
获取单个角色 信息(含人设)。
const char = await storvia.characters.get("秦照野");
// { name, avatar, description, introduction, visibleAtStart, userDescription, gender, isPreset }characters.add(character)
添加新 角色。gender 必填,取值 'male' | 'female' | 'other'。
await storvia.characters.add({
name: "新角色",
description: "一个神秘的路人",
gender: "other", // 必填
avatar: "img/stranger.png", // 可选
});characters.update(name, data)
更新 角色信息。规则:
- 预设角色(
isPreset: true):description(作者设定)不可修改;userDescription(用户补充)、avatar、gender可修改 - 非预设角色:
description、userDescription、avatar、gender均可修改 introduction/visibleAtStart是作者预设资产,所有角色都不可通过 SDK 修改(仅创作台 +/sync同步)- 所有非预设角色的
description+ 所有角色的userDescription合计上限 10000 字符
// 为预设角色添加用户补充人设
await storvia.characters.update("秦照野", { userDescription: "对我温柔一些" });
// 非预设角色可改 description
await storvia.characters.update("路人甲", { description: "神秘的陌生人" });
// 改头像
await storvia.characters.update("秦照野", { avatar: "img/new-avatar.png" });
// 改性别
await storvia.characters.update("秦照野", { gender: "male" });characters.remove(name)
删除角色。
await storvia.characters.remove("新角色");characters.detail(name)
获取 角色完整信息(人设 + 属性状态)。属性值为 RichFieldValue 格式。
const detail = await storvia.characters.detail("秦照野");
// {
// name: "秦照野",
// avatar: "https://...",
// description: "", // 预设角色固定为空;自建角色为用户撰写
// introduction: "对外介绍文本", // 仅预设角色有意义,只读
// visibleAtStart: true, // 仅预设角色有意义,只读
// userDescription: "用户补充",
// gender: "male",
// isPreset: true,
// state: {
// "档案": {
// "心情": { value: "happy", type: "text" },
// "好感度": { value: 45, type: "number", min: 0, max: 100 }
// }
// }
// }characters.state.get(name)
获取角色的属性状态。不传 group 返回全部分组,传 group 返回该组数据(与 player.state.get() 对称)。
// 获取全部分组
const all = await storvia.characters.state.get("秦照野");
// {
// "档案": {
// "心情": { value: "happy", type: "text" },
// "好感度": { value: 45, type: "number", min: 0, max: 100 }
// },
// "身份": {
// "粉丝牌": { value: "真爱粉", type: "text" }
// }
// }
// 获取单个分组
const profile = await storvia.characters.state.get("秦照野", "档案");characters.state.update(name, group, values)
更新角色指定分组下的字段。传入字段与该分组已有数据合并。只需传简单值,系统自动保留字段元数据(type/min/max)并钳位。
await storvia.characters.state.update("秦照野", "档案", {
心情: "happy",
好感度: 50, // 自动钳位到 [0, 100]
});分组名和字段名必须和创作台中配置的完全一致(包括中英文、空格等)。
characters.setPriority(name, value)
调整 角色在场景中的重要程度。范围 0-100(超出自动钳位到 0 或 100),越高表示越不容易被挤出场景。
当会话中的角色 数量超过上限时,系统会把 priority 最低的角色移入休眠池。
预设角色的 priority 固定为 100,不可修改(调用会返回错误)。
// 让某个角色 变得重要
await storvia.characters.setPriority("路人甲", 80);
// 让 角色退居二线(下次触发上限裁剪时会被优先移除)
await storvia.characters.setPriority("过客", 10);等价写法:storvia.characters.state.update('路人甲', { priority: 80 })。setPriority 是这种用法的显式快捷方法,类型和错误提示更明确。
storvia.relationships — 关系
关系是两个角色之间的定向连接,由 from + to 唯一标识。每条关系可以有自定义字段(对应创作台配置的关系字段)。
from / to 涉及玩家时必须使用 "玩家",与你通过
storvia.player.update({ name: "..." }) 设置的实际玩家名无关。所有
relationships.list/get/add/update/remove 接口都遵循此约定,例如:
await storvia.relationships.update("玩家", "秦照野", { 好感度: 50 });使用其它值无法定位到玩家相关的关系。
relationships.list()
获取所有关系。
const rels = await storvia.relationships.list();
// [
// { from: "玩家", to: "秦照野", "好感度": 45, "关系阶段": "朋友" },
// { from: "玩家", to: "宋亦", "好感度": 30, "关系阶段": "认识" },
// ]relationships.get(from, to)
获取两个角色之间的关系。
const rel = await storvia.relationships.get("玩家", "秦照野");
// { from: "玩家", to: "秦照野", "好感度": 45, "关系阶段": "朋友" }relationships.add(relationship)
添加新关系。
await storvia.relationships.add({
from: "玩家",
to: "新角色",
好感度: 0,
关系阶段: "陌生",
});relationships.update(from, to, data)
更新关系字段。合并更新。
await storvia.relationships.update("玩家", "秦照野", {
好感度: 50,
关系阶段: "朋友",
});relationships.remove(from, to)
删除关系。
await storvia.relationships.remove("玩家", "新角色");关系是单向的:from:"玩家" to:"秦照野" 和 from:"秦照野" to:"玩家"
是两条不同的关系。如果需要双向关系,需要分别创建和更新。
storvia.inventory — 物品栏
数据结构:Record<分组名, Record<物品名, { count, desc?, iconUrl? }>>。
创作台里配置的分组在运行时始终保留(即使清空所有物品也不会消失),和 player.state / characters.state 的行为一致。
物品总数上限 20 件,达到上限后新增会被拒绝(SDK 和 AI 都一样),需先 remove 释放空间。
inventory.list()
获取整个物品栏,或指定分组下的物品。创作台里为预设物品配置的图标会随 iconUrl 字段返回完整 URL;没配置图标的物品缺省 iconUrl。
// 全部
const all = await storvia.inventory.list();
// {
// "礼物": { "玫瑰花": { count: 3, desc: "送给主播的礼物", iconUrl: "https://.../rose.png" } },
// "装备": {}, // 空分组也会保留
// "仓库": { "宝箱": { count: 1, iconUrl: "https://.../chest.png" } }
// }
// 单个分组
const gifts = await storvia.inventory.list("礼物");
// { "玫瑰花": { count: 3, desc: "...", iconUrl: "https://.../rose.png" } }创作台里为预设物品配置的图标会在首次同步时写入存档,list() 会直接返回带
iconUrl 的数据。如果没有配置图标,字段为 undefined。
inventory.add(options)
参数:{ group, name, count?, desc?, iconUrl? }。
新增物品。group 必须是已存在的分组(创作时定义,或先用 ensureGroup 创建);同分组下 name 唯一。iconUrl 支持 http/https 图片地址或 Storvia 的 storage:// 路径。
await storvia.inventory.add({
group: "礼物",
name: "玫瑰花",
count: 5,
desc: "送给主播的礼物",
iconUrl: "https://example.com/rose.png", // 可选
});inventory.update(options)
参数:{ group, name, count?, desc?, iconUrl? }。
更新物品字段。group 和 name 是必填(用于定位物品),其余字段(count / desc / iconUrl)按需传入,合并更新,未传的保持不变。传空字符串不会清除 iconUrl,现阶段要"去掉图标"需要先 remove 再 add。
// 同时更新多个字段
await storvia.inventory.update({
group: "礼物",
name: "玫瑰花",
count: 10,
desc: "新描述",
iconUrl: "https://example.com/rose-v2.png",
});inventory.remove(options)
参数:{ group, name }。
删除单个物品。分组本身保留,即使变空也不会消失。
await storvia.inventory.remove({ group: "礼物", name: "玫瑰花" });inventory.move(options)
参数:{ fromGroup, toGroup, name, newName? }。
在分组间移动物品,可选择同时改名。事务完成,不会因中途失败导致物品丢失。
// 把随身的药水移到仓库
await storvia.inventory.move({
fromGroup: "随身",
toGroup: "仓库",
name: "生命药水",
});inventory.ensureGroup(group)
幂等地确保分组存在。用于运行时动态创建创作时未定义的分组。
await storvia.inventory.ensureGroup("临时物品栏");inventory.removeGroup(group, options?)
第二参数:{ cascade?: boolean }。
显式删除整个分组。默认非空分组会报错;传 cascade: true 连带物品一起删。
await storvia.inventory.removeGroup("临时物品栏"); // 仅空分组
await storvia.inventory.removeGroup("临时物品栏", { cascade: true }); // 强制删除从 SDK v0.2.0 起,物品栏的数据结构从"扁平数组 + group 字段"改为"分组 →
物品名
Record"。创作时定义的分组现在会永久保留,不再因为物品清空而消失。如果你从旧版本升级,需要更新调用方式(所有方法都改为对象参数)。
storvia.custom — 扩展属性
扩展属性存储游戏中的额外变量。字段类型只支持 文本 / 数值,可选分组(分组的子字段也只能是文本/数值)。支持两种用法:
- 纯 SDK 数据 — 不注入 AI,仅游戏代码读写(如关卡进度、计数器)
- AI 追踪数据 — inject 状态开启时字段值会注入 AI 提示词,AI 每轮自动更新
AI 追踪可以双端控制:
- 创作台:字段级 / 分组级开关,作为新增字段的初始 inject 状态
- SDK:运行时调用
setInject(key, value)或set(data, { inject: true })动态切换 - 分组的 AI 追踪是整组开关:开启后组内所有子字段都被 AI 看到
- 调用
/sync时只会为新增 key 写入作者最新的 inject 默认值;已有 key 的 inject 状态由 SDK 自由控制,/sync不再覆盖 - 需要存任意 JSON、永不被 AI 看到?请用
storvia.save
限制
| 项目 | 限制 |
|---|---|
| 字段总数(平铺 + 所有分组内字段) | 无限制——可建任意多字段 |
| 注入 AI 的字段数(rules + state 值) | 100 个——按作者填写顺序累计,超出的不进 prompt、不进 state XML |
| 字段类型 | 仅 文本 / 数值 |
| 单字符串值长度 | 无限制——按 token 计费自然约束成本 |
注入 AI 的字段数达到 100 后,AI 动态新增字段(op="add")会被拒绝;其余非注入字段不计入这个上限,可继续随意读写。控制"哪些字段被注入"用 inject 开关 + 场景设定 组合:把字段绑到特定场景,AI 只在该场景看到。
custom.get(key?)
获取扩展属性。不传参数返回全部,传 key 返回指定字段。
// 获取全部
const all = await storvia.custom.get();
// { chapter: 3, bgm: "rain", endings: { he: false, be: true } }
// 获取单个字段
const chapter = await storvia.custom.get("chapter");
// 3custom.set(data, options?)
深合并更新。平铺字段直接覆盖,分组字段合并子字段(不会丢失未传入的子字段)。options.inject 可一次性把这次写入的所有 key 标记为对应 inject 状态。
// 更新平铺字段:推进到第 4 章
await storvia.custom.set({ chapter: 4 });
// 更新分组内的字段(只改 he,be 保持不变)
await storvia.custom.set({ endings: { he: true } });
// 写入并同时开启 AI 追踪
await storvia.custom.set({ chapter: 4 }, { inject: true });custom.setInject(key, inject)
单独切换某个顶层 key 的 AI 追踪状态(不修改值)。分组的 setInject 等价于整组开关。
await storvia.custom.setInject("chapter", true); // 开启注入
await storvia.custom.setInject("endings", false); // 整组关闭注入custom.getInject()
读取当前所有顶层 key 的 inject 状态(同步方法)。
const injectMap = storvia.custom.getInject();
// { chapter: true, endings: false }custom.delete(key)
删除一个平铺字段或整个分组。
// 删除平铺字段
await storvia.custom.delete("bgm");
// 删除整个分组
await storvia.custom.delete("endings");custom.setGroupField(groupKey, fieldKey, value)
更新分组内的单个字段。如果分组不存在会自动创建。
await storvia.custom.setGroupField("endings", "se", true);custom.deleteGroupField(groupKey, fieldKey)
删除分组内的单个字段。分组本身会保留(即使字段全空),不会自动消失。如需删除整个分组请调用 custom.delete(groupKey)。
await storvia.custom.deleteGroupField("endings", "be");AI 追踪
inject 状态决定字段是否注入 AI 提示词。开启后:
- 字段的当前值会注入到 AI 提示词中,AI 能感知这个数据
- AI 每轮回复时会自动更新该字段(和角色属性、物品栏一样)
两种控制方式(任选其一或组合使用):
- 创作台静态配置——在「自定义属性」区域,每个平铺字段或分组有一个「AI」开关。分组开关是整组开关,开启后组内所有子字段都注入。
- SDK 运行时切换——
storvia.custom.setInject(key, value)或set(data, { inject: true })动态切换。
配合「场景设定」:创作台为字段或分组配置场景设定后,字段只在指定场景下注入(如 viewer_count 只在直播场景注入)。SDK 只能切 inject 开关,场景设定始终来自创作台配置。
/sync 行为:增量同步——只会为新增 key 写入作者最新的 inject 默认值。已有 key(不论是作者预设还是 AI/SDK 运行时新增)的 inject 状态保留,/sync 不再覆盖。所以 SDK 调 setInject(key, value) 之后即使 /sync 也不会被回退。
适用场景:
- AI 追踪:剧情进度、任务阶段、密室锁定状态 等需要 AI 自动维护的变量
- 纯 SDK:UI 主题、音量、调试开关 等纯前端逻辑数据
扩展属性单字符串字段值无长度上限——按 token 计费的成本会自然约束过长内容的使用。
storvia.state — 完整游戏状态
一次性返回当前会话所有模块(world / player / characters / inventory / relationships)的合并快照。适合渲染整体属性面板、做存档导出、或调试时观察当前游戏状态。
state.get()
const snapshot = await storvia.state.get();返回值
{
current: PublicCurrentState, // 当前活跃模块的合并快照
previous: PublicCurrentState | null, // 上一轮的 current(用于 before/after 对比)
dormant: { // 因角色数量超出上限被移入休眠区的数据
characters: Record<string, CharacterState>,
relationships: Array<Record<string, unknown>>,
}
}会话尚未初始化时返回 null。
完整 JSON 示例
{
"current": {
"world": {
"time": "晚上 22:00",
"date": "2024年3月15日",
"location": "秦照野的直播间",
"region": "江南水乡",
"weather": "小雨"
},
"player": {
"attributes": {
"基础": {
"等级": { "value": 5, "type": "number", "min": 1, "max": 100 },
"经验": { "value": 180, "type": "number", "min": 0, "max": 9999 }
},
"经济": {
"花园币": { "value": 450, "type": "number", "min": 0, "max": 99999 }
}
}
},
"characters": {
"秦照野": {
"isPreset": true,
"priority": 100,
"avatar": "https://cdn.storvia.com/avatars/qzy.png",
"gender": "male",
"attributes": {
"档案": {
"好感度": { "value": 50, "type": "number", "min": 0, "max": 100 },
"心情": { "value": "开心", "type": "text" }
}
}
},
"路人甲": {
"isPreset": false,
"priority": 60,
"gender": "other",
"attributes": {
"档案": {
"好感度": { "value": 0, "type": "number", "min": 0, "max": 100 }
}
}
}
},
"inventory": {
"礼物": {
"玫瑰花": { "count": 3, "desc": "送给主播的礼物", "icon_url": "https://cdn.storvia.com/items/rose.png" }
},
"装备": {}
},
"relationships": [
{ "from": "玩家", "to": "秦照野", "好感度": 50, "关系阶段": "朋友" }
]
},
"previous": {
"world": { "time": "晚上 21:00", "...": "..." },
"player": { "...": "..." },
"characters": { "...": "..." },
"inventory": { "...": "..." },
"relationships": []
},
"dormant": {
"characters": {
"过客": {
"isPreset": false,
"priority": 10,
"attributes": { "档案": { "好感度": { "value": 5, "type": "number" } } }
}
},
"relationships": []
}
}字段说明
current.world— 扁平 KV,对应storvia.world.get()current.player.attributes— 按分组的玩家属性,对应storvia.player.state.get()current.characters[name].attributes— 按分组的角色属性,对应storvia.characters.state.get(name);isPreset/priority/avatar/gender为顶层 meta 字段current.inventory— 分组 → 物品名 →{ count, desc?, icon_url? }current.relationships— 关系数组,每条形如{ from, to, ...自定义字段 }previous— 与current同结构,但是 AI 上一轮回复前的快照;首次对话时为nulldormant.characters— 休眠的角色(priority较低、被挤出活跃区的);不会注入 AI,AI 也不会更新这些角色
和 chat 响应里 full 的关系:storvia.chat.send() / generate() / retry() 在 AI 本轮有属性变更时,会在响应里携带同样结构的 full 字段。两者数据结构完全一致,区别在于:
chat.*的full是对话响应顺带返回——AI 改了什么自动给你storvia.state.get()是主动拉取——任意时刻取当前最新值
该方法在预览模式下无法正常使用,需要发布后在 Storvia 平台测试。 预览会话不持久化到数据库;调用会抛出 StorviaError(code: NOT_SUPPORTED_IN_PREVIEW)。预览阶段需要查看状态时,用各分模块的 get() 单独读取(如 storvia.world.get() / storvia.player.state.get())。
storvia.save — 游戏存档
save 是作者自由读写的任意 JSON,专供游戏运行状态持久化。和 custom 的关键区别:
| 特性 | custom | save |
|---|---|---|
| 数据类型 | 仅文本/数值(可分组) | 任意合法 JSON(嵌套对象、数组、布尔均可) |
| AI 注入 | 可选(创作台开启 AI 追踪时) | 永不注入 |
| 配额 | 共享 100 字段上限 | 独立配额,不计入 custom |
| 大小上限 | 单字符串无上限 | 整个存档序列化后 ≤ 256KB |
| 写入语义 | 深合并(分组合并子字段) | 整体覆写 |
save.get()
读取整个存档对象。第一次调用(未写入过)返回 {}。
const save = await storvia.save.get();
// {} 或上次写入的对象save.set(data)
整体覆写存档。增量更新需要自行 get → 修改 → set。
// 典型存档场景
await storvia.save.set({
chapter: 3,
cursor: { x: 120, y: 340 },
flags: { metAlice: true, doorUnlocked: false },
inventory: [
{ id: "key_red", count: 1 },
{ id: "potion", count: 5 },
],
history: ["scene_intro", "scene_market"],
meta: { savedAt: Date.now(), version: 2 },
});
// 增量更新:先读再改
const cur = await storvia.save.get();
cur.flags.doorUnlocked = true;
await storvia.save.set(cur);存档大小上限为 256KB(JSON.stringify(data).length),超出会返回
SAVE_DATA_TOO_LARGE。如果你的游戏需要存储更多状态(如完整地图数据),考虑只存关键索引,详细内容用
localStorage 或后端服务存储。
禁止把图片本体(base64 / dataURL / 二进制等)直接写入 save!
一张图片就能轻松占用几百 KB 到几 MB,远远超过 256KB 上限,会直接导致 save.set() 失败、玩家整局存档丢失。
正确做法:把图片上传到图床或对象存储,save 里只存图片的 URL / 路径。比如:
// ❌ 错误:把整张图塞进去
await storvia.save.set({ avatar: "data:image/png;base64,iVBORw0KG..." });
// ✅ 正确:只存路径
await storvia.save.set({ avatar: "https://cdn.example.com/avatars/u123.png" });同理适用于音频、视频、PDF 等任意二进制资源——save 的所有字段只用来存轻量结构化数据(数字、布尔、短文本、引用 URL),永远不要存原始资源本身。
storvia.memory — AI 记忆
读取/编辑当前会话的 AI 记忆——也就是聊天界面"AI 记忆"对话框里那段长期总结,会自动注入每一轮对话提示词,用于跨长对话保持剧情连贯。
- 覆写语义:
update(content)用新内容整体替换旧记忆,写入时自动trim
关于自动总结(开发中)
目前 world-engine 后端不会自动为通过 SDK 创建的会话生成 AI 记忆——memory.get() 在你(或玩家)首次手动 update 之前会一直返回 null。如果你的游戏需要长期记忆能力来跨长对话保持剧情连贯,请在剧情关键节点自行调用 storvia.memory.update(...) 写入。
平台正在开发新版自动总结方案,上线后会按消息数阈值在后台自动生成总结并写入此字段,作者代码无需变更即可受益。进度会在 更新日志 公告。
返回类型
interface AISummary {
content: string; // 记忆内容
updated_at: string; // ISO 时间戳,最近一次写入时间
}memory.get() → Promise<AISummary | null>
读取当前会话的 AI 记忆。首次未生成时返回 null。
const m = await storvia.memory.get();
// null 或:
// { content: "主角进入山洞后揭开了……", updated_at: "2026-05-06T10:00:00.000Z" }memory.update(content) → Promise<AISummary>
整体覆写记忆内容,返回写入后的最新结构。
const updated = await storvia.memory.update("主角揭开了山洞中的秘密,与伙伴重逢。");
// { content: "主角揭开了山洞中的秘密,与伙伴重逢。", updated_at: "..." }update 是覆写而非追加。如需在原记忆基础上扩写,请先 get 取出旧 content,自行拼接后再 update。
storvia.getAssets() — 素材库
平台级方法(非会话模块),用于获取官方素材库中的头像和物品图标。
getAssets(type, category?)
按类型获取素材列表,可选按分类过滤。
参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
type | 'avatar' | 'icon' | 是 | 素材类型:头像或物品图标 |
category | string | 否 | 分类名称,不传则返回全部(分类待更新) |
返回值:Promise<AssetItem[]>
interface AssetItem {
id: number;
name: string;
url: string;
assetType: "avatar" | "icon";
category: string;
}示例:
// 获取所有头像素材
const avatars = await storvia.getAssets("avatar");
// [
// { id: 1, name: "骑士", url: "https://...", assetType: "avatar", category: "奇幻" },
// { id: 2, name: "法师", url: "https://...", assetType: "avatar", category: "奇幻" },
// ...
// ]
// 按分类获取物品图标
const weapons = await storvia.getAssets("icon", "武器");
// 用获取到的素材设置角色头像
const avatar = avatars[0];
await storvia.characters.update("骑士", { avatar: avatar.url });素材库数据由平台官方维护。
数据应该放哪里?
| 需求 | 推荐模块 |
|---|---|
| 需要 AI 感知的角色/世界/物品状态 | world / player.state / characters.state / relationships / inventory |
| 需要 AI 感知的简单变量(剧情进度、好感度等) | custom(创作台开启 AI 追踪) |
| 不需要 AI 感知的简单 KV(计数器、开关) | custom(创作台关闭 AI 追踪) |
| 游戏运行状态、UI 缓存、复杂结构 | save(不占 custom 配额,永不注入 AI) |