文件检查点跟踪在代理会话期间通过 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,然后稍后恢复会话以回退文件。下面详细解释了每个步骤。
这些模式显示了根据您的用例捕获和使用检查点 UUID 的不同方式。
此模式仅保留最新的检查点 UUID,在每个代理轮次之前更新它。如果处理过程中出现问题,您可以立即回退到最后的安全状态并跳出循环。
如果 Claude 在多个轮次中进行更改,您可能想回退到特定点而不是一直回退。例如,如果 Claude 在第一轮重构文件,在第二轮添加测试,您可能想保留重构但撤销测试。
此模式将所有检查点 UUID 存储在带有元数据的数组中。会话完成后,您可以回退到任何先前的检查点:
这个完整的示例创建一个小实用程序文件,让代理添加文档注释,显示更改,然后询问您是否想回退。
在开始之前,请确保您已安装 Claude Agent SDK。
文件检查点具有以下限制:
| 限制 | 描述 |
|---|---|
| 仅 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 进程的连接关闭。
解决方案:使用空提示恢复会话,然后在新查询上调用回退:
# Resume session with empty prompt, then rewind
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() 方法。import asyncio
import os
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, UserMessage, ResultMessage
async def main():
# Step 1: Enable checkpointing
options = ClaudeAgentOptions(
enable_file_checkpointing=True,
permission_mode="acceptEdits", # Auto-accept file edits without prompting
extra_args={"replay-user-messages": None}, # Required to receive checkpoint UUIDs in the response stream
env={**os.environ, "CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING": "1"}
)
checkpoint_id = None
session_id = None
# Run the query and capture checkpoint UUID and session ID
async with ClaudeSDKClient(options) as client:
await client.query("Refactor the authentication module")
# Step 2: Capture checkpoint UUID from the first user message
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
# Step 3: Later, rewind by resuming the session with an empty prompt
if checkpoint_id and session_id:
async with ClaudeSDKClient(ClaudeAgentOptions(
enable_file_checkpointing=True,
resume=session_id
)) as client:
await client.query("") # Empty prompt to open the connection
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():
# Update checkpoint on each user message (keeps the latest)
if isinstance(message, UserMessage) and message.uuid:
checkpoint_id = message.uuid
# Capture session ID from the result message
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("") # Empty prompt to open the connection
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>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():
# Update checkpoint before each agent turn starts
# This overwrites the previous checkpoint. Only keep the latest
if isinstance(message, UserMessage) and message.uuid:
safe_checkpoint = message.uuid
# Decide when to revert based on your own logic
# For example: error detection, validation failure, or user input
if your_revert_condition and safe_checkpoint:
await client.rewind_files(safe_checkpoint)
# Exit the loop after rewinding, files are restored
break
asyncio.run(main())import asyncio
import os
from dataclasses import dataclass
from datetime import datetime
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, UserMessage, ResultMessage
# Store checkpoint metadata for better tracking
@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
# Later: rewind to any checkpoint by resuming the session
if checkpoints and session_id:
target = checkpoints[0] # Pick any checkpoint
async with ClaudeSDKClient(ClaudeAgentOptions(
enable_file_checkpointing=True,
resume=session_id
)) as client:
await client.query("") # Empty prompt to open the connection
async for message in client.receive_response():
await client.rewind_files(target.id)
break
print(f"Rewound to: {target.description}")
asyncio.run(main())创建测试文件
创建一个名为 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():
# Configure the SDK with checkpointing enabled
# - enable_file_checkpointing: Track file changes for rewinding
# - permission_mode: Auto-accept file edits without prompting
# - extra_args: Required to receive user message UUIDs in the stream
options = ClaudeAgentOptions(
enable_file_checkpointing=True,
permission_mode="acceptEdits",
extra_args={"replay-user-messages": None}
)
checkpoint_id = None # Store the user message UUID for rewinding
session_id = None # Store the session ID for resuming
print("Running agent to add doc comments to utils.py...\n")
# Run the agent and capture checkpoint data from the response stream
async with ClaudeSDKClient(options) as client:
await client.query("Add doc comments to utils.py")
async for message in client.receive_response():
# Capture the first user message UUID - this is our restore point
if isinstance(message, UserMessage) and message.uuid and not checkpoint_id:
checkpoint_id = message.uuid
# Capture the session ID so we can resume later
if isinstance(message, ResultMessage):
session_id = message.session_id
print("Done! Open utils.py to see the added doc comments.\n")
# Ask the user if they want to rewind the changes
if checkpoint_id and session_id:
response = input("Rewind to remove the doc comments? (y/n): ")
if response.lower() == "y":
# Resume the session with an empty prompt, then rewind
async with ClaudeSDKClient(ClaudeAgentOptions(
enable_file_checkpointing=True,
resume=session_id
)) as client:
await client.query("") # Empty prompt opens the connection
async for message in client.receive_response():
await client.rewind_files(checkpoint_id) # Restore files
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)。当代理添加文档注释时,您将看到文件实时更新,然后当您选择回退时恢复到原始状态。
export CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING=1
python try_checkpointing.py您将看到代理添加文档注释,然后出现一个提示询问您是否想回退。如果您选择是,文件将恢复到其原始状态。