文件检查点功能会跟踪代理会话期间通过 Write、Edit 和 NotebookEdit 工具所做的文件修改,允许您将文件回退到任何先前状态。想要试试看?跳转到交互式示例。
通过检查点功能,您可以:
只有通过 Write、Edit 和 NotebookEdit 工具所做的更改会被跟踪。通过 Bash 命令(如 echo > file.txt 或 sed -i)所做的更改不会被检查点系统捕获。
当您启用文件检查点功能时,SDK 会在通过 Write、Edit 或 NotebookEdit 工具修改文件之前创建备份。响应流中的用户消息包含一个检查点 UUID,您可以将其用作恢复点。
检查点与代理用于修改文件的以下内置工具配合使用:
| 工具 | 描述 |
|---|---|
| Write | 创建新文件或用新内容覆盖现有文件 |
| Edit | 对现有文件的特定部分进行有针对性的编辑 |
| NotebookEdit | 修改 Jupyter 笔记本(.ipynb 文件)中的单元格 |
文件回退会将磁盘上的文件恢复到先前状态。它不会回退对话本身。调用 rewindFiles()(TypeScript)或 rewind_files()(Python)后,对话历史和上下文保持不变。
检查点系统跟踪:
当您回退到某个检查点时,创建的文件会被删除,修改的文件会恢复到该时间点的内容。
要使用文件检查点功能,请在选项中启用它,从响应流中捕获检查点 UUID,然后在需要恢复时调用 rewindFiles()(TypeScript)或 rewind_files()(Python)。
以下示例展示了完整的流程:启用检查点、从响应流中捕获检查点 UUID 和会话 ID,然后稍后恢复会话以回退文件。每个步骤在下面都有详细说明。
import asyncio
import os
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, UserMessage, ResultMessage
async def main():
# 步骤 1:启用检查点
options = ClaudeAgentOptions(
enable_file_checkpointing=True,
permission_mode="acceptEdits", # 自动接受文件编辑,无需提示
extra_args={"replay-user-messages": None}, # 需要此选项才能在响应流中接收检查点 UUID
env={**os.environ, "CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING": "1"}
)
checkpoint_id = None
session_id = None
# 运行查询并捕获检查点 UUID 和会话 ID
async with ClaudeSDKClient(options) as client:
await client.query("Refactor the authentication module")
# 步骤 2:从第一条用户消息中捕获检查点 UUID
async for message in client.receive_response():
if isinstance(message, UserMessage) and message.uuid and not checkpoint_id:
checkpoint_id = message.uuid
if isinstance(message, ResultMessage) and not session_id:
session_id = message.session_id
# 步骤 3:稍后,通过恢复会话并使用空提示来回退
if checkpoint_id and session_id:
async with ClaudeSDKClient(ClaudeAgentOptions(
enable_file_checkpointing=True,
resume=session_id
)) as client:
await client.query("") # 空提示以打开连接
async for message in client.receive_response():
await client.rewind_files(checkpoint_id)
break
print(f"Rewound to checkpoint: {checkpoint_id}")
asyncio.run(main())设置环境变量
文件检查点功能需要 CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING 环境变量。您可以在运行脚本之前通过命令行设置它,也可以直接在 SDK 选项中设置。
选项 1:通过命令行设置
export CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING=1选项 2:在 SDK 选项中设置
在配置 SDK 时通过 env 选项传递环境变量:
import os
options = ClaudeAgentOptions(
enable_file_checkpointing=True,
env={**os.environ, "CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING": "1"}
)启用检查点
配置您的 SDK 选项以启用检查点并接收检查点 UUID:
| 选项 | Python | TypeScript | 描述 |
|---|---|---|---|
| 启用检查点 | enable_file_checkpointing=True | enableFileCheckpointing: true | 跟踪文件更改以便回退 |
| 接收检查点 UUID | extra_args={"replay-user-messages": None} | extraArgs: { 'replay-user-messages': null } | 需要此选项才能在流中获取用户消息 UUID |
options = ClaudeAgentOptions(
enable_file_checkpointing=True,
permission_mode="acceptEdits",
extra_args={"replay-user-messages": None}
)
async with ClaudeSDKClient(options) as client:
await client.query("Refactor the authentication module")捕获检查点 UUID 和会话 ID
设置 replay-user-messages 选项后(如上所示),响应流中的每条用户消息都有一个 UUID,可作为检查点。
对于大多数用例,捕获第一条用户消息的 UUID(message.uuid);回退到该点会将所有文件恢复到原始状态。要存储多个检查点并回退到中间状态,请参阅多个恢复点。
捕获会话 ID(message.session_id)是可选的;只有在流完成后想要稍后回退时才需要它。如果您在处理消息时立即调用 rewindFiles()(如在风险操作前设置检查点中的示例所做的那样),则可以跳过捕获会话 ID。
checkpoint_id = None
session_id = None
async for message in client.receive_response():
# 在每条用户消息上更新检查点(保留最新的)
if isinstance(message, UserMessage) and message.uuid:
checkpoint_id = message.uuid
# 从结果消息中捕获会话 ID
if isinstance(message, ResultMessage):
session_id = message.session_id回退文件
要在流完成后回退,请使用空提示恢复会话,然后使用您的检查点 UUID 调用 rewind_files()(Python)或 rewindFiles()(TypeScript)。您也可以在流处理期间回退;有关该模式,请参阅在风险操作前设置检查点。
async with ClaudeSDKClient(ClaudeAgentOptions(
enable_file_checkpointing=True,
resume=session_id
)) as client:
await client.query("") # 空提示以打开连接
async for message in client.receive_response():
await client.rewind_files(checkpoint_id)
break如果您捕获了会话 ID 和检查点 ID,也可以从 CLI 回退:
claude --resume <session-id> --rewind-files <checkpoint-uuid>这些模式展示了根据您的用例捕获和使用检查点 UUID 的不同方式。
此模式仅保留最新的检查点 UUID,在每个代理轮次之前更新它。如果处理过程中出现问题,您可以立即回退到最后的安全状态并跳出循环。
import asyncio
import os
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, UserMessage
async def main():
options = ClaudeAgentOptions(
enable_file_checkpointing=True,
permission_mode="acceptEdits",
extra_args={"replay-user-messages": None},
env={**os.environ, "CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING": "1"}
)
safe_checkpoint = None
async with ClaudeSDKClient(options) as client:
await client.query("Refactor the authentication module")
async for message in client.receive_response():
# 在每个代理轮次开始前更新检查点
# 这会覆盖之前的检查点。只保留最新的
if isinstance(message, UserMessage) and message.uuid:
safe_checkpoint = message.uuid
# 根据您自己的逻辑决定何时回退
# 例如:错误检测、验证失败或用户输入
if your_revert_condition and safe_checkpoint:
await client.rewind_files(safe_checkpoint)
# 回退后退出循环,文件已恢复
break
asyncio.run(main())如果 Claude 在多个轮次中进行更改,您可能希望回退到特定时间点而不是一直回退到最开始。例如,如果 Claude 在第一轮重构了一个文件,在第二轮添加了测试,您可能希望保留重构但撤销测试。
此模式将所有检查点 UUID 与元数据一起存储在数组中。会话完成后,您可以回退到任何先前的检查点:
import asyncio
import os
from dataclasses import dataclass
from datetime import datetime
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, UserMessage, ResultMessage
# 存储检查点元数据以便更好地跟踪
@dataclass
class Checkpoint:
id: str
description: str
timestamp: datetime
async def main():
options = ClaudeAgentOptions(
enable_file_checkpointing=True,
permission_mode="acceptEdits",
extra_args={"replay-user-messages": None},
env={**os.environ, "CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING": "1"}
)
checkpoints = []
session_id = None
async with ClaudeSDKClient(options) as client:
await client.query("Refactor the authentication module")
async for message in client.receive_response():
if isinstance(message, UserMessage) and message.uuid:
checkpoints.append(Checkpoint(
id=message.uuid,
description=f"After turn {len(checkpoints) + 1}",
timestamp=datetime.now()
))
if isinstance(message, ResultMessage) and not session_id:
session_id = message.session_id
# 稍后:通过恢复会话回退到任何检查点
if checkpoints and session_id:
target = checkpoints[0] # 选择任何检查点
async with ClaudeSDKClient(ClaudeAgentOptions(
enable_file_checkpointing=True,
resume=session_id
)) as client:
await client.query("") # 空提示以打开连接
async for message in client.receive_response():
await client.rewind_files(target.id)
break
print(f"Rewound to: {target.description}")
asyncio.run(main())这个完整的示例创建一个小型工具文件,让代理添加文档注释,向您展示更改,然后询问您是否要回退。
在开始之前,请确保您已安装 Claude Agent SDK。
创建测试文件
创建一个名为 utils.py(Python)或 utils.ts(TypeScript)的新文件,并粘贴以下代码:
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def multiply(a, b):
return a * b
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b运行交互式示例
在与工具文件相同的目录中创建一个名为 try_checkpointing.py(Python)或 try_checkpointing.ts(TypeScript)的新文件,并粘贴以下代码。
此脚本要求 Claude 为您的工具文件添加文档注释,然后给您选择回退并恢复原始文件的选项。
import asyncio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, UserMessage, ResultMessage
async def main():
# 配置启用检查点的 SDK
# - enable_file_checkpointing:跟踪文件更改以便回退
# - permission_mode:自动接受文件编辑,无需提示
# - extra_args:需要此选项才能在流中接收用户消息 UUID
options = ClaudeAgentOptions(
enable_file_checkpointing=True,
permission_mode="acceptEdits",
extra_args={"replay-user-messages": None}
)
checkpoint_id = None # 存储用于回退的用户消息 UUID
session_id = None # 存储用于恢复的会话 ID
print("Running agent to add doc comments to utils.py...\n")
# 运行代理并从响应流中捕获检查点数据
async with ClaudeSDKClient(options) as client:
await client.query("Add doc comments to utils.py")
async for message in client.receive_response():
# 捕获第一条用户消息 UUID - 这是我们的恢复点
if isinstance(message, UserMessage) and message.uuid and not checkpoint_id:
checkpoint_id = message.uuid
# 捕获会话 ID 以便稍后恢复
if isinstance(message, ResultMessage):
session_id = message.session_id
print("Done! Open utils.py to see the added doc comments.\n")
# 询问用户是否要回退更改
if checkpoint_id and session_id:
response = input("Rewind to remove the doc comments? (y/n): ")
if response.lower() == "y":
# 使用空提示恢复会话,然后回退
async with ClaudeSDKClient(ClaudeAgentOptions(
enable_file_checkpointing=True,
resume=session_id
)) as client:
await client.query("") # 空提示打开连接
async for message in client.receive_response():
await client.rewind_files(checkpoint_id) # 恢复文件
break
print("\n✓ File restored! Open utils.py to verify the doc comments are gone.")
else:
print("\nKept the modified file.")
asyncio.run(main())此示例演示了完整的检查点工作流程:
enable_file_checkpointing=True 和 permission_mode="acceptEdits" 配置 SDK 以自动批准文件编辑rewind_files() 来恢复原始文件运行示例
设置环境变量并从与工具文件相同的目录运行脚本。
在运行脚本之前,在 IDE 或编辑器中打开您的工具文件(utils.py 或 utils.ts)。您将看到文件在代理添加文档注释时实时更新,然后在您选择回退时恢复到原始状态。
您将看到代理添加文档注释,然后出现提示询问您是否要回退。如果您选择是,文件将恢复到原始状态。
文件检查点功能有以下限制:
| 限制 | 描述 |
|---|---|
| 仅限 Write/Edit/NotebookEdit 工具 | 通过 Bash 命令所做的更改不会被跟踪 |
| 同一会话 | 检查点与创建它们的会话绑定 |
| 仅限文件内容 | 创建、移动或删除目录不会通过回退撤销 |
| 本地文件 | 远程或网络文件不会被跟踪 |
如果 enableFileCheckpointing 或 rewindFiles() 不可用,您可能使用的是较旧的 SDK 版本。
解决方案:更新到最新的 SDK 版本:
pip install --upgrade claude-agent-sdknpm install @anthropic-ai/claude-agent-sdk@latest如果 message.uuid 为 undefined 或缺失,说明您没有接收到检查点 UUID。
原因:未设置 replay-user-messages 选项。
解决方案:在选项中添加 extra_args={"replay-user-messages": None}(Python)或 extraArgs: { 'replay-user-messages': null }(TypeScript)。
当指定的用户消息 UUID 不存在检查点数据时,会出现此错误。
常见原因:
CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING 环境变量解决方案:确保您已设置环境变量(参见设置环境变量),然后使用示例中展示的模式:捕获第一条用户消息 UUID,完全完成会话,然后使用空提示恢复并调用一次 rewindFiles()。
当您在完成响应迭代后调用 rewindFiles() 或 rewind_files() 时,会出现此错误。循环完成后,与 CLI 进程的连接会关闭。
解决方案:使用空提示恢复会话,然后在新查询上调用回退:
# 使用空提示恢复会话,然后回退
async with ClaudeSDKClient(ClaudeAgentOptions(
enable_file_checkpointing=True,
resume=session_id
)) as client:
await client.query("")
async for message in client.receive_response():
await client.rewind_files(checkpoint_id)
breakquery() 的所有选项和 rewindFiles() 方法。ClaudeAgentOptions 的所有选项和 rewind_files() 方法。Was this page helpful?