跳转到主要内容

Documentation Index

Fetch the complete documentation index at: https://docs.qoder.com/llms.txt

Use this file to discover all available pages before exploring further.

enableFileCheckpointingquery() 的 options 参数之一,用来让 CLI 在工具修改文件前后做快照;启用后,调用方可以用 q.rewindFiles(userMessageId, ...) 把文件回滚到某条用户消息开始处理时的状态。这两件事必须配合使用:没启用 checkpoint,rewind 不可用。

启用文件 checkpoint

import { query } from '@qoder-ai/qoder-agent-sdk';

const q = query({
  prompt: 'Refactor src/foo.ts into a cleaner implementation',
  options: {
    cwd: '/path/to/project',
    enableFileCheckpointing: true,
    allowedTools: ['Read', 'Edit', 'Write'],
    permissionMode: 'acceptEdits',
  },
});
进阶:通过 settings 同时调整其他 CLI 配置时 query() 的 options 还支持一个 settings 字段,可以传一个 Settings 对象,也可以传一个 settings 文件的绝对路径字符串。它和 enableFileCheckpointing 的关系如下:
  • settings 对象时,SDK 会把 general.fileCheckpointing.enabled = true 自动合并进去,无需手动写。
  • settings 文件路径字符串时,SDK 不会改写文件内容,需要你自己在该文件中配置:
{
  "general": {
    "fileCheckpointing": {
      "enabled": true
    }
  }
}
只设置 enableFileCheckpointing: true、不传 settings,对于纯粹只用 rewind 的场景已经够用。

使用显式 user message id

Rewind 以用户消息 ID 为锚点。需要精确回滚时,建议用结构化输入并自己生成 uuid,这样 UI 才能稳定反查「回到那条消息之前」。
import { randomUUID } from 'node:crypto';
import { query } from '@qoder-ai/qoder-agent-sdk';

const userMessageId = randomUUID();

async function* input() {
  yield {
    type: 'user' as const,
    uuid: userMessageId,
    parent_tool_use_id: null,
    message: {
      role: 'user' as const,
      content: [
        {
          type: 'text' as const,
          text: 'Rewrite notes.txt as a two-line summary.',
        },
      ],
    },
  };

  // If your application needs to call rewind later within the same session,
  // keep yielding subsequent user inputs here instead of closing the stream.
}

const q = query({
  prompt: input(),
  options: {
    cwd: '/path/to/project',
    enableFileCheckpointing: true,
    allowedTools: ['Read', 'Write'],
    permissionMode: 'acceptEdits',
  },
});

Dry run 预览

先 dry run 可以看到是否能回滚、会影响哪些文件,以及整体的插入/删除统计。Dry run 不会修改文件。 返回的 RewindFilesResult 包含以下字段:
字段类型说明
canRewindboolean是否可以执行回滚。dry run 失败时不抛错,由该字段标记
errorstring?canRewind=false 时的诊断文案,可直接展示给用户
filesChangedstring[]?受影响文件的绝对路径列表,可用于在 UI 中列出每一个将要被回滚的文件
insertionsnumber?回滚动作总共会“撤销新增”的行数(汇总值)
deletionsnumber?回滚动作总共会“撤销删除”的行数(汇总值)
当前 SDK 只在 RewindFilesResult 中返回受影响的文件列表与汇总的行级统计,不会返回每个文件的具体 diff。如果你需要展示每文件的差异,可以在 dry run 后基于 filesChanged 自己读取磁盘内容并与 checkpoint 内容比对,或在执行 rewind 后用 git/工作区对比工具呈现。
const preview = await q.rewindFiles(userMessageId, { dryRun: true });

if (!preview.canRewind) {
  // Show the diagnostic message in the UI.
  console.error(preview.error);
  return;
}

// Overall stats across all affected files.
console.log({
  files: preview.filesChanged?.length ?? 0,
  insertions: preview.insertions ?? 0,
  deletions: preview.deletions ?? 0,
});

// Per-file listing — useful for a confirmation dialog.
for (const file of preview.filesChanged ?? []) {
  console.log(`will be reverted: ${file}`);
}

执行回滚

const result = await q.rewindFiles(userMessageId);
console.log(result.filesChanged);

失败语义

调用形式不可回滚时的表现
rewindFiles(id, { dryRun: true })resolve 一个 { canRewind: false, error },便于在 UI 上展示诊断
rewindFiles(id)(执行模式)Promise reject,调用方建议用 try/catch 展示失败原因
try {
  await q.rewindFiles(userMessageId);
} catch (error) {
  console.error(error instanceof Error ? error.message : String(error));
}

Options 速查

字段类型说明
enableFileCheckpointingboolean启用文件 checkpoint,供 rewindFiles() 使用
settingsstring | Settings传给 CLI 的 settings;传对象时 SDK 会合并 general.fileCheckpointing.enabled

返回值参考

type RewindFilesResult = {
  canRewind: boolean;
  error?: string;
  filesChanged?: string[];
  insertions?: number;
  deletions?: number;
};

最佳实践

  • 保存 user message id:需要回滚能力的应用应在发送消息时保存 uuid,不要依赖 UI 文本反查。
  • Rewind 前先 dry run:先展示影响范围,再让用户确认执行回滚。
  • 回滚后刷新 UI:rewind 只改文件,不改会话历史,UI 需要根据 filesChanged 自行重新加载相关视图。
  • 失败时给用户看到 errorcanRewind=false 时的 error 文案通常能直接展示给最终用户做诊断。