すべての変更を元に戻せるようにする
エージェントで「元に戻す」とは、各書き込みが何を置き換えたかを記録して、ファイルを以前の任意の段階に戻せるようにすることです。エージェントは七段階目で間違え、その間違いが見えるのは九段階目です。
変更の記録があれば、六段階目まで巻き戻せます。なければ、差分を読んで当て推量をします。
このレッスンのゴール
メモ
実行のすべての変更を記録して、ファイルを任意の段階まで巻き戻せる。
キーワード
| ことば | いみ |
|---|---|
| スナップショット | 変更の前に取っておく、ファイルのコピー |
| 変更の記録 | すべての変更を、順に並べた一覧 |
| 段階 | 実行の中の、番号の付いた一つの操作 |
| 元に戻す | ファイルを、もとの状態に戻すこと |
| 巻き戻し | 選んだ段階より後の変更を、すべて元に戻すこと |
| 以前の中身 | 書き込みの前にファイルが持っていた内容 |
学生が入力するセルは、このプレビューでは空白です。
元に戻すことは、再開ではない
チェックポイントは、止まった実行を再開できるように保存します。それは前へ進むことです。「元に戻す」は、ファイルを後ろへ、もとの状態に戻します。
二つは、別の記録を持ちます。チェックポイントは、エージェントの状態を持ちます。変更の記録は、各書き込みが何を置き換えたかを持ちます。
以前の中身を記録する
書き込みや削除の前に、段階の番号、パス、ファイルの中身を記録します。ファイルがなかったときは、それも「なし」として記録します。
段階 n まで戻すには、記録を最後から段階 n + 1 まで順にたどります。以前の中身を一つずつ戻します。以前が「なし」なら、ファイルを取り除きます。最後のものから順にします。そうしないと、同じファイルへの二つの編集が、逆の順に戻ってしまいます。
計算例: 四つの段階
| 段階 | 操作 | 以前の中身 |
|---|---|---|
| 1 | app.py を書く | x = 1 |
| 2 | new.py を書く | なし: 存在しなかった |
| 3 | notes.txt を削除する | あとで |
| 4 | app.py を書く | x = 2 |
学生が入力するセルは、このプレビューでは空白です。
よくある間違い
注意
多くの人は、git だけでエージェントを元に戻せると考えます。git が戻せるのは、コミットまでです。コミットのない実行の六段階目には戻れませんし、追跡していないファイルは無視します。書き込みごとに、自分の記録を持ちます。
変更の記録を書く(1)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const files = { \"app.py\": \"x = 1\", \"notes.txt\": \"あとで\" };' 'const ops = [' ' { op: \"write\", path: \"app.py\", text: \"x = 2\" },' ' { op: \"write\", path: \"new.py\", text: \"y = 1\" },' ' { op: \"delete\", path: \"notes.txt\" },' ' { op: \"write\", path: \"app.py\", text: \"x = 3\" },' '];' 'function copy(f) { return Object.assign({}, f); }' > undo5.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
変更の記録を書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' '// 各 op の前に、ファイルの中身を記録する。中身の文字列、なければ null。' 'function applyRun(start, list) {' ' const now = copy(start);' ' const log = [];' ' list.forEach(function (o, i) {' ' log.push({ step: i + 1, path: o.path, before: o.path in now ? now[o.path] : null });' ' if (o.op === \"write\") now[o.path] = o.text;' ' else delete now[o.path];' ' });' ' return { files: now, log: log };' '}' >> undo5.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
変更の記録を書く(3)
docker exec -w /home/node/project agent sh -c "printf '%s\n' '// ある段階より後の記録を、最後のものから順に元に戻す。' 'function undoTo(now, log, step) {' ' const back = copy(now);' ' for (const e of log.slice().reverse()) {' ' if (e.step <= step) continue;' ' if (e.before === null) delete back[e.path];' ' else back[e.path] = e.before;' ' }' ' return back;' '}' >> undo5.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
変更の記録を書く(4)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function show(label, f) { console.log(label + \" \" + JSON.stringify(f)); }' 'const run = applyRun(files, ops);' 'show(\"開始\", files);' 'show(\"4 段階の後\", run.files);' 'show(\"3 まで戻す\", undoTo(run.files, run.log, 3));' 'show(\"1 まで戻す\", undoTo(run.files, run.log, 1));' 'show(\"0 まで戻す\", undoTo(run.files, run.log, 0));' 'console.log(\"記録: \" + run.log.map(function (e) { return e.step + \":\" + e.path; }).join(\" \"));' >> undo5.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
実行して巻き戻す
docker exec -w /home/node/project agent node undo5.jsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
ここでは、ファイルは辞書
ファイルはスクリプトの中の辞書にあるので、ディスクは何も変わりません。本物のハーネスは本物のファイルに書き、記録は専用のファイルか保存先に持ちます。
この Run はモデルを呼ばないので、補助は要らず、代わりに使うものもありません。
Run の出力
| 行 | 示すこと |
|---|---|
| 開始 {"app.py":"x = 1","notes.txt":"あとで"} | 実行の前のファイル |
| 4 段階の後 {"app.py":"x = 3","new.py":"y = 1"} | 実行が書き、足し、削除した |
| 3 まで戻す {"app.py":"x = 2","new.py":"y = 1"} | 段階 4 だけが元に戻った |
| 1 まで戻す {"app.py":"x = 2","notes.txt":"あとで"} | 段階 2 から 4 が元に戻った |
| 0 まで戻す ... | 開始のときのファイル |
| 記録: 1:app.py 2:new.py 3:notes.txt 4:app.py | 段階ごとに一つの記録 |
学生が入力するセルは、このプレビューでは空白です。