メインコンテンツへスキップ

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.

ファイル checkpoint は、1 回のセッションでツールが変更したローカルファイルの状態を記録するために使用されます。有効化すると、ホストアプリケーションは QoderSDKClient.rewind_files(user_message_id, ...) を呼び出して、追跡対象のファイルを特定のユーザーメッセージの処理開始時の状態へロールバックできます。 この 2 つの機能は連携して使用する必要があります。enable_file_checkpointing=True を有効化していない場合、rewind_files() には利用可能なファイルスナップショットが存在しません。

ファイル checkpoint の有効化

enable_file_checkpointingQoderAgentOptions のフィールドです。後続でロールバックが必要な場合は、QoderSDKClient で同じアクティブなセッションを保ち、options で checkpoint を有効化します:
from qoder_agent_sdk import QoderAgentOptions, QoderSDKClient


options = QoderAgentOptions(
    cwd="/path/to/project",
    enable_file_checkpointing=True,
    extra_args={"replay-user-messages": None},
    allowed_tools=["Read", "Edit", "Write"],
    permission_mode="acceptEdits",
)

async with QoderSDKClient(options=options) as client:
    await client.query("Refactor src/foo.py into a cleaner implementation.")
    async for message in client.receive_response():
        ...
extra_args={"replay-user-messages": None} は checkpoint を有効化するスイッチではありません。これはレスポンスストリーム内で UserMessage をリプレイし、ロールバックのアンカーとなる uuid を含めるためのものです。アプリケーションでユーザーが「このターンの前に戻る」を選択できるようにする場合は、通常これも同時に設定すべきです。

checkpoint ID の取得

rewind_files() はユーザーメッセージ ID をアンカーとして使用します。Python SDK では、レスポンスストリームの UserMessage.uuid からこの ID を取得するのが一般的です:
from qoder_agent_sdk import (
    QoderAgentOptions,
    QoderSDKClient,
    ResultMessage,
    UserMessage,
)


options = QoderAgentOptions(
    cwd="/path/to/project",
    enable_file_checkpointing=True,
    extra_args={"replay-user-messages": None},
    allowed_tools=["Write"],
    permission_mode="acceptEdits",
)

checkpoint_id: str | None = None

async with QoderSDKClient(options=options) as client:
    await client.query("Rewrite notes.txt as a two-line summary.")

    async for message in client.receive_response():
        if (
            isinstance(message, UserMessage)
            and message.uuid
            and message.parent_tool_use_id is None
        ):
            checkpoint_id = message.uuid

        if isinstance(message, ResultMessage) and message.is_error:
            raise RuntimeError(message.result or "Query failed.")

    if checkpoint_id is None:
        raise RuntimeError("No user message UUID was returned.")
checkpoint_id はユーザーメッセージの uuid であり、session_id でも ResultMessage の ID でもありません。これは当該 checkpoint を生成したセッションのコンテキスト内でのみ有効です。他のセッションではこの ID を直接ロールバックに使用できません。

Dry run プレビュー

ロールバックを実行する前に、まず dry_run=True で影響範囲をプレビューすることを推奨します。Dry run はファイルを変更しないため、確認ダイアログや監査ログに適しています。
preview = await client.rewind_files(checkpoint_id, dry_run=True)

if not preview["canRewind"]:
    print(preview.get("error", "Unable to rewind files."))
else:
    print(
        {
            "files": len(preview.get("filesChanged", [])),
            "insertions": preview.get("insertions", 0),
            "deletions": preview.get("deletions", 0),
        }
    )

    for file_path in preview.get("filesChanged", []):
        print(f"will be reverted: {file_path}")
RewindFilesResult には以下のフィールドが含まれます:
フィールド説明
canRewindboolロールバックを実行できるかどうか。dry run 失敗時は例外を投げず、このフィールドで示される
errorstrcanRewind=False 時の診断メッセージ
filesChangedlist[str]これから復元される、または既に復元されたファイルパスのリスト
insertionsintロールバック動作で取り消される追加行数の合計
deletionsintロールバック動作で取り消される削除行数の合計
現在の戻り値には影響を受けたファイルリストと行レベルの集計統計のみが含まれており、ファイルごとの具体的な diff は返しません。ファイルごとの差分を表示する必要がある場合は、まず dry run で filesChanged を取得し、独自のワークスペース diff ロジックと組み合わせて表示してください。

ロールバックの実行

影響範囲を確認したら、dry_run を渡さずにロールバックを実行できます:
result = await client.rewind_files(checkpoint_id)

if result["canRewind"]:
    print(result.get("filesChanged", []))
ロールバックは checkpoint で追跡されたローカルファイルの状態のみを復元し、会話履歴をロールバックすることはありません。つまり、モデルは以前のセッションのコンテキストを引き続き保持しています。UI は filesChanged に基づいてエディタ、ファイルツリー、または diff ビューを自身でリフレッシュする必要があります。

失敗のセマンティクス

呼び出し形式ロールバック不可時の動作
await client.rewind_files(id, dry_run=True){"canRewind": False, "error": ...} を返し、診断を直接表示するのに適する
await client.rewind_files(id)例外を投げるため、呼び出し元はキャッチして失敗理由を表示すべき
try:
    await client.rewind_files(checkpoint_id)
except Exception as exc:
    print(str(exc))
よくある失敗原因:enable_file_checkpointing が有効化されていない、渡された ID が有効なユーザーメッセージ UUID ではない、その ID が現在のセッションに属していない、対象メッセージにロールバック可能なファイルスナップショットが存在しない。

Settings との関係

QoderAgentOptions.settingsenable_file_checkpointing と同時に使用できます:
options = QoderAgentOptions(
    cwd="/path/to/project",
    settings={"theme": "dark"},
    enable_file_checkpointing=True,
)
enable_file_checkpointing=True の場合、SDK は CLI に渡される settings に general.fileCheckpointing.enabled = True をマージします。既に他の settings フィールドが存在する場合は保持されます。既に fileCheckpointing 設定が存在する場合は、enabled は SDK オプションが優先されます。

境界

  • ローカルファイル checkpoint のみをロールバックします。MCP ツール、リモートサービス、データベースなどの外部副作用は取り消されません。
  • Bash を介して直接ファイルに書き込まれた変更は、ロールバック可能なファイルスナップショットとしては扱われません。
  • ファイル内容は復元できますが、ディレクトリ作成のようなディレクトリレベルの副作用は必ずしも取り消されません。
  • checkpoint ID はセッションに紐付きます。同じセッションを復元すれば対応する ID を引き続き使用できますが、異なるセッション間では混用できません。

フィールドクイックリファレンス

エントリ説明
QoderAgentOptions.enable_file_checkpointing`boolNone`ファイル checkpoint を有効化し、rewind_files() で使用
QoderAgentOptions.extra_args`dict[str, strNone]`{"replay-user-messages": None} を渡すとストリームで UserMessage.uuid を取得可能
QoderSDKClient.rewind_files(user_message_id, dry_run=False)async methodファイルロールバックのプレビューまたは実行

ベストプラクティス

  • ユーザーメッセージ UUID を保存するUserMessage.uuid を UI のメッセージ記録に紐付け、テキスト内容で逆引きするのを避けてください。
  • 先に dry run、その後実行:影響を受けるファイルと統計を先に表示し、ユーザーに確認させてからロールバックしてください。
  • ロールバック後に UI をリフレッシュfilesChanged に基づいて関連ファイル状態を再ロードしてください。
  • 失敗時に error を表示:dry run が返す error は通常、ユーザー向け診断としてそのまま使用できます。