Was this page helpful?
Контрольные точки файлов отслеживают изменения файлов, сделанные через инструменты 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 закрывается при завершении цикла.
Решение: Возобновите сеанс с пустым запросом, затем вызовите отмену на новом запросе:
# Возобновите сеанс с пустым запросом, затем отмените
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():
# Шаг 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"Отменено до контрольной точки: {checkpoint_id}")
asyncio.run(main())Установите переменную окружения
Контрольные точки файлов требуют переменную окружения CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING. Вы можете установить её либо через командную строку перед запуском вашего скрипта, либо непосредственно в опциях SDK.
Вариант 1: Установка через командную строку
export CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING=1Вариант 2: Установка в опциях SDK
Передайте переменную окружения через опцию env при настройке SDK:
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Отмена файлов
Чтобы отменить после завершения потока, возобновите сеанс с пустым запросом и вызовите rewind_files() (Python) или rewindFiles() (TypeScript) с вашим UUID контрольной точки. Вы также можете отменить во время потока; см. Контрольная точка перед рискованными операциями для этого паттерна.
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 сеанса и UUID контрольной точки, вы также можете отменить из 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():
# Обновляйте контрольную точку перед началом каждого хода агента
# Это перезаписывает предыдущую контрольную точку. Сохраняйте только последнюю
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())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"Отменено до: {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():
# Настройте 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("Запуск агента для добавления комментариев документации к 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("Готово! Откройте utils.py, чтобы увидеть добавленные комментарии документации.\n")
# Спросите пользователя, хочет ли он отменить изменения
if checkpoint_id and session_id:
response = input("Отменить, чтобы удалить комментарии документации? (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✓ Файл восстановлен! Откройте utils.py, чтобы проверить, что комментарии документации удалены.")
else:
print("\nСохранен измененный файл.")
asyncio.run(main())Этот пример демонстрирует полный рабочий процесс контрольных точек:
enable_file_checkpointing=True и permission_mode="acceptEdits" для автоматического одобрения правок файловrewind_files() для восстановления исходного файлаЗапустите пример
Установите переменную окружения и запустите скрипт из того же каталога, что и ваш служебный файл.
Откройте ваш служебный файл (utils.py или utils.ts) в вашей IDE или редакторе перед запуском скрипта. Вы увидите, как файл обновляется в реальном времени, когда агент добавляет комментарии документации, затем вернется к оригиналу, когда вы выберете отмену.
Вы увидите, как агент добавляет комментарии документации, затем появится запрос, спрашивающий, хотите ли вы отменить. Если вы выберете да, файл восстанавливается в его исходное состояние.