做一个 Electron 长任务助手,“继续讨论”“回到旧节点”“保留 A 另试 B”应当是三个不同动作。一个含糊的“恢复”按钮会让用户难以判断原讨论是否保留,也会让开发者把读取历史、替换历史和创建新会话混在一起。
Tansr SDK 在 Electron 主进程运行;检查点、resume、restore 和 fork 为这些动作提供会话机制,界面与方案列表仍由应用设计。先把按钮含义、会话标识与保存行为对齐,再决定页面如何呈现结果,才能做出可继续的方案比较体验。SDK 与 Electron 运行条件、检查点与恢复
三个用户动作,对应三个不同接口含义
| 用户想做的事 | 对应机制 | 对会话历史的影响 |
|---|---|---|
| 明天继续讨论方案 A | SessionStore+resume | 读取 A 已保存的历史,接着讨论 |
| 放弃 A 的后续讨论,回到共同起点 | restore | 在同一会话中,以检查点替换当前历史 |
| 保留 A,同时尝试方案 B | fork | 创建一条新会话记录,A 保持原状 |
这三种动作应在界面中使用不同表达,例如“继续讨论”“回到这个节点”“从这里另开方案”。用户可以据此判断现有讨论是否保留,开发者也不必用一个含糊的“恢复”按钮承载所有行为。
应用还需要维护少量产品信息:每条方案的显示名称、归属用户,以及 B 来自哪个会话和检查点。它们用来呈现方案列表与来源关系,属于应用的数据设计;不能只根据模型生成的标题来确定会话归属。真正读取和保存历史时,以对应会话标识为准。
先选对共同起点,再创建分支
以一个正在开发的桌面活动策划助手为例。用户已经明确三项约束:活动面向老客户、预算上限已确定、筹备期为两周。接下来,方案 A 采用线下交流,方案 B 尝试线上活动。
检查点应放在共同约束已经完整进入对话、具体方案尚未展开的位置。这样两条方案共享需求,而不会把“选定线下场地”等只属于 A 的内容带进 B。
可以把预期历史画成下表:
| 时点 | 原会话 A 中的历史 | 新会话 B 中的历史 |
|---|---|---|
| 保存共同起点 P | 需求、预算、期限;P 记录到这里 | 尚未创建 |
| 完成方案 A | 共同需求+线下方案+对 A 的追问 | 尚未创建 |
| 从 P 创建分支 | 保持方案 A 的全部现有历史 | 从 P 的共同需求开始 |
| 继续方案 B | 继续独立保留 A | 共同需求+线上方案+对 B 的追问 |
在 Tansr 中,手动 checkpoint 用来保存这个上下文节点;fork 从检查点建立新会话记录,并保留源会话。应用需要接入会话存储,才能安放新分支。手动保存检查点还应等待当前执行轮空闲;运行中调用不会排队等待,而会返回相应错误。检查点的存储与空闲期语义
共同起点的位置比“有没有分支按钮”更关键。若用户是在方案 A 完成后才提出分支,而产品此前没有留下所需节点,就不能假定任意一条旧消息都已经具备可恢复的快照。产品可以让用户确认并重新整理共同需求,再建立新的讨论起点。
再次打开时,要同时做到读回与继续保存
SDK 默认会话在内存中。跨进程继续讨论,需要使用 SessionStore 保存会话,并保存应用与会话标识的对应关系。用户再次选择方案 A 或 B 时,再读取各自记录。
这里有一个容易漏掉的区别:resume 指定从哪里恢复,store 指定后续历史写到哪里。只配置恢复读取,不代表用户新一轮讨论还会继续保存。产品应同时安排这两件事,才能兑现“今天关掉,明天还能接着讨论”的体验。会话存储与恢复配置
恢复失败也要保持含义清楚。session_not_found 表示目标记录不存在,可以让用户决定是否另开;session_store_corrupted 表示存储损坏,应保留资料并处理存储问题。把两种情况都吞掉后显示空白对话,会让用户误以为保存过的方案从未存在。
自建存储时,回退必须真正替换旧历史
如果应用把 SessionStore 接到自己的数据库,还要处理一个会直接影响结果的约定:commit 收到 rewritten = true 时,应按完整的新历史替换保存内容,不能仅按消息条数追加。压缩或检查点恢复都可能改写历史前缀。自建 SessionStore 的提交约定
假设会话原来保存着“共同需求+方案 A+三轮修改”,用户选择回到共同起点 P:
| 存储处理 | 再次打开时可能得到什么 |
|---|---|
| 只把新收到的消息追加在旧历史后 | 旧方案和已放弃的修改仍可能被读回,界面与实际上下文不一致 |
| 收到整体改写标记后保存完整替换结果 | 重新读取的历史与当前已恢复的共同起点一致 |
这不是给历史删几行的界面操作。产品显示“已回到共同起点”,存储层也必须保存同一份历史;否则重启后旧内容可能重新出现。采用内置文件存储时,由它按 SDK 的存储机制处理;选择自建存储时,这项契约就是实现的一部分。
让按钮完成的事与用户理解一致
实现方案切换时,可以围绕上述场景核对四个结果:
- 从 P 创建 B 后,再打开 A,仍能看到 A 的后续讨论。
- B 从共同需求开始,不混入 A 独有的方案内容。
- A、B 分别继续讨论并关闭应用后,再次打开仍各自保留新增内容。
- 对 A 执行回退并保存后,重新读取的是恢复后的历史,而不是此前被放弃的讨论。
未接快照存储时,restore 会以 store_not_wired 拒绝恢复,应先补齐快照存储。restore 也要求会话处于空闲状态。运行中请求会被拒绝,不会自动排队;界面应在当前任务结束后再执行恢复,并根据实际结果更新显示,而不是先把按钮变成“恢复成功”。
这些机制改变的是助手使用的会话上下文。如果方案 A 已经通过业务工具预订场地,另开 B 或回到旧节点都不会撤销预订。把“讨论方案”和“确认执行”做成清楚的业务动作,用户才可以放心比较,而不会把切换方案误解为撤销现实中的操作。
对于需要长期讨论和多方案比较的 Node.js 或 Electron 产品,Tansr 提供了可接入自家存储与界面的会话机制。开发者可以围绕“继续哪条记录、替换哪段历史、保留哪个原方案”设计交互,再对照检查点与恢复文档落实接口与存储约定。