文件 checkpoint 用来记录一次会话里被工具修改过的本地文件状态。启用
Python 需要后续回滚时,使用
Rewind 以用户消息 ID 为锚点,两个 SDK 获取方式不同:
回滚锚点是用户消息的
执行回滚前,建议先 dry run 预览影响范围:是否能回滚、会影响哪些文件,以及整体的插入/删除统计。Dry run 不会修改文件,适合做确认弹窗或审计日志。
返回的
确认影响范围后,不传 dry run 参数即可执行回滚:
回滚只恢复被 checkpoint 追踪到的本地文件状态,不会回滚对话历史。也就是说,模型仍然保留之前会话里的上下文;UI 需要根据
常见失败原因包括:没有启用文件 checkpoint、传入的 ID 不是有效用户消息 UUID、该 ID 不属于当前会话、目标消息没有可回滚的文件快照。
options 里的
只设置 checkpoint 开关、不传
enableFileCheckpointing(TypeScript)/ enable_file_checkpointing(Python)后,调用方可以用 rewindFiles(userMessageId, ...) / rewind_files(user_message_id, ...) 把文件回滚到某条用户消息开始处理时的状态。
这两个能力需要配合使用:没启用 checkpoint,rewind 没有可用的文件快照。
启用文件 checkpoint
QoderSDKClient 保持同一个活跃会话。示例中的 extra_args={"replay-user-messages": None} 不是启用 checkpoint 的开关,它的作用是让响应流里回放 UserMessage,并带上可作为回滚锚点的 uuid——如果你的应用需要让用户点选「回到这一轮之前」,通常应该同时设置它。
获取回滚锚点:user message ID
Rewind 以用户消息 ID 为锚点,两个 SDK 获取方式不同:
- TypeScript:需要精确回滚时,建议用结构化输入并自己生成
uuid,这样 UI 才能稳定反查「回到那条消息之前」。 - Python:常见做法是从响应流里的
UserMessage.uuid捕获这个 ID(配合extra_args={"replay-user-messages": None})。
uuid,不是 session_id,也不是 result 消息的 ID。它只在产生该 checkpoint 的会话上下文中有效;其他会话不能拿这个 ID 直接回滚。
Dry run 预览
执行回滚前,建议先 dry run 预览影响范围:是否能回滚、会影响哪些文件,以及整体的插入/删除统计。Dry run 不会修改文件,适合做确认弹窗或审计日志。
返回的 RewindFilesResult 包含以下字段:
| 字段 | 类型 | 说明 |
|---|---|---|
canRewind | boolean | 是否可以执行回滚。dry run 失败时不抛错,由该字段标记 |
error | string? | canRewind 为 false 时的诊断文案,可直接展示给用户 |
filesChanged | string[]? | 受影响文件的绝对路径列表,可用于在 UI 中列出每一个将要被回滚的文件 |
insertions | number? | 回滚动作总共会"撤销新增"的行数(汇总值) |
deletions | number? | 回滚动作总共会"撤销删除"的行数(汇总值) |
当前 SDK 只在RewindFilesResult中返回受影响的文件列表与汇总的行级统计,不会返回每个文件的具体 diff。如果你需要展示每文件的差异,可以在 dry run 后基于filesChanged自己读取磁盘内容并与 checkpoint 内容比对,或在执行 rewind 后用 git/工作区对比工具呈现。
执行回滚
确认影响范围后,不传 dry run 参数即可执行回滚:
filesChanged 自行刷新编辑器、文件树或 diff 视图。
失败语义
| 调用形式 | 不可回滚时的表现 |
|---|---|
dry run 模式(rewindFiles(id, { dryRun: true }) / rewind_files(id, dry_run=True)) | 返回 { canRewind: false, error },便于在 UI 上展示诊断 |
执行模式(rewindFiles(id) / rewind_files(id)) | TypeScript 中 Promise reject;Python 中抛出异常。调用方应捕获并展示失败原因 |
Settings 关系
options 里的 settings 字段可以和文件 checkpoint 开关同时使用。它可以传一个 Settings 对象,也可以传一个 settings 文件的绝对路径字符串:
- 传
settings对象时,SDK 会把general.fileCheckpointing.enabled = true自动合并进去,无需手动写。如果已有其他 settings 字段,它们会被保留;如果已有fileCheckpointing配置,enabled会以 SDK 选项为准。 - 传 settings 文件路径字符串时,SDK 不会改写文件内容,需要你自己在该文件中配置:
settings,对于纯粹只用 rewind 的场景已经够用。
边界
- 只回滚本地文件 checkpoint;MCP 工具、远程服务或数据库等外部副作用不会被撤销。
- 通过
Bash直接写文件的变更不作为可回滚文件快照处理。 - 文件内容可以恢复;目录创建这类目录级副作用不一定会被撤销。
- checkpoint ID 与会话绑定。恢复同一会话后可以继续使用对应 ID;不同会话之间不可混用。
字段速查
| 入口(TypeScript / Python) | 说明 |
|---|---|
enableFileCheckpointing / enable_file_checkpointing | 启用文件 checkpoint,供 rewind 使用 |
settings / settings | 传给 CLI 的 settings;传对象时 SDK 会合并 general.fileCheckpointing.enabled |
extra_args(仅 Python) | 传 {"replay-user-messages": None} 可在流里拿到 UserMessage.uuid |
q.rewindFiles(userMessageId, { dryRun }) / client.rewind_files(user_message_id, dry_run=False) | 预览或执行文件回滚 |
返回值参考
最佳实践
- 保存 user message ID:需要回滚能力的应用应在发送消息时保存
uuid(Python 中把UserMessage.uuid和你的 UI 消息记录绑定起来),不要依赖 UI 文本反查。 - Rewind 前先 dry run:先展示影响范围,再让用户确认执行回滚。
- 回滚后刷新 UI:rewind 只改文件,不改会话历史,UI 需要根据
filesChanged自行重新加载相关视图。 - 失败时给用户看到
error:canRewind为 false 时的error文案通常能直接展示给最终用户做诊断。