Plus facile à lire avec un fond crème, une teinte, plus de contraste ou un texte plus grand ? Choisissez vos couleurs et votre texte, une fois pour toutes les pages.

Leçon gratuite

Instantané et retour arrière d’un dossier

Après cette leçon: Je peux remettre un dossier comme il était avant l’action d’un agent.

Leçon de 65 min7 commandesLab agent de code IA : utiliser opencode pour expliquer et corriger du code, et vérifier son travail

Remettre un dossier comme il était

Un instantané est une copie de chaque fichier d’un dossier, prise avant qu’un agent agisse. Un retour arrière remet le dossier dans l’état de cette copie.

C’est utile, car même un agent confiné peut abîmer les fichiers qu’il a le droit de toucher. Avec un instantané, vous pouvez dire : remettez tout, exactement.

À la fin de cette leçon

Remarque

Je peux remettre un dossier comme il était avant l’action d’un agent.

Mots clés

MotCe que ça veut dire
Instantanéune copie de chaque fichier et de son texte
Différencela liste de ce qui a changé entre deux états
Restaurerremettre des fichiers à partir d’un instantané
Retour arrièreune restauration de tout le dossier
Fichier ajoutéun fichier qui n’était pas dans l’instantané

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Un instantané contient chaque fichier

Avant que l’agent commence, lisez chaque fichier du dossier et gardez son chemin et son texte. Gardez la copie là où l’agent ne peut pas aller.

Comparez par chemin. Après l’action, un fichier est ajouté s’il est nouveau, supprimé s’il a disparu, et modifié si son texte est différent.

Exemple détaillé : trois modifications

Modification de l’agentDans la différencePour le remettre
A écrit src/app.js avec un nouveau texteModifiéÉcrire l’ancien texte
A supprimé notes.txtSuppriméÉcrire de nouveau le fichier
A créé nouveau.txtAjoutéLe supprimer
A réécrit un fichier avec son ancien texteRienRien à faire

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Une erreur courante

Attention

Beaucoup pensent qu’une restauration n’a qu’à réécrire les fichiers modifiés. Elle doit aussi supprimer les fichiers que l’agent a ajoutés, sinon le dossier n’est pas comme avant. Puis vérifiez : après la restauration, la différence doit être vide.

Prouver que la restauration a marché

Une restauration que vous ne vérifiez pas est un espoir. Après avoir restauré, prenez un nouvel instantané et comparez-le au premier. Si la différence est vide, le dossier est exactement comme avant.

Cela compare les fichiers seulement. Un dossier vide créé par l’agent n’est pas dans une liste de fichiers : dites ce que votre instantané ne couvre pas.

Écrire l’assistant du modèle, partie 1

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// Les jetons d’une réponse, ou null si elle n’en donne pas.' 'function compter(donnees, nom) {' '  return donnees.usage && typeof donnees.usage[nom] === \"number\" ? donnees.usage[nom] : null;' '}' > model.js"

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Écrire l’assistant du modèle, partie 2

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function demander(messages, echantillon, max) {' '  try {' '    const res = await fetch(base + \"/v1/chat/completions\", {' '      method: \"POST\",' '      headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' '      body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"statut \" + res.status);' '    const d = await res.json();' '    return { texte: d.choices[0].message.content, entree: compter(d, \"prompt_tokens\"), sortie: compter(d, \"completion_tokens\"), enregistre: false };' '  } catch (erreur) {' '    console.log(\"Échantillon enregistré : aucun modèle n’a répondu (\" + erreur.message + \").\");' '    return { texte: echantillon, entree: null, sortie: null, enregistre: true };' '  }' '}' 'module.exports = { demander };' >> model.js"

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Écrire le script de retour arrière, partie 1

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander } = require(\"./model\");' 'const fs = require(\"fs\");' 'const path = require(\"path\");' 'const racine = path.join(process.cwd(), \"labo-retour\");' 'function poser(rel, texte) {' '  const f = path.join(racine, rel);' '  fs.mkdirSync(path.dirname(f), { recursive: true });' '  fs.writeFileSync(f, texte);' '}' 'function noms(dossier) {' '  let sortie = [];' '  for (const n of fs.readdirSync(dossier).sort()) {' '    const f = path.join(dossier, n);' '    sortie = fs.statSync(f).isDirectory() ? sortie.concat(noms(f)) : sortie.concat([f]);' '  }' '  return sortie;' '}' > retour.js"

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Écrire le script de retour arrière, partie 2

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function prendre() {' '  const s = {};' '  noms(racine).forEach(function (f) { s[path.relative(racine, f)] = fs.readFileSync(f, \"utf8\"); });' '  return s;' '}' 'function difference(a, b) {' '  const d = { ajoutes: [], modifies: [], supprimes: [] };' '  Object.keys(b).forEach(function (k) { if (a[k] === undefined) d.ajoutes.push(k); else if (a[k] < b[k] || a[k] > b[k]) d.modifies.push(k); });' '  Object.keys(a).forEach(function (k) { if (b[k] === undefined) d.supprimes.push(k); });' '  return d;' '}' 'function restaurer(copie) {' '  const actuel = prendre();' '  Object.keys(actuel).forEach(function (k) { if (copie[k] === undefined) fs.rmSync(path.join(racine, k)); });' '  Object.keys(copie).forEach(function (k) { poser(k, copie[k]); });' '}' >> retour.js"

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Écrire le script de retour arrière, partie 3

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'fs.rmSync(racine, { recursive: true, force: true });' 'poser(\"src/app.js\", \"let x = 1;\");' 'poser(\"src/util.js\", \"export {};\");' 'poser(\"notes.txt\", \"a faire\");' >> retour.js"

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Écrire le script de retour arrière, partie 4

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const copie = prendre();' '  console.log(\"instantané : \" + Object.keys(copie).join(\" \"));' '  poser(\"src/app.js\", \"let x = 2;\");' '  fs.rmSync(path.join(racine, \"notes.txt\"));' '  poser(\"nouveau.txt\", \"bonjour\");' '  console.log(\"changements : \" + JSON.stringify(difference(copie, prendre())));' '  restaurer(copie);' '  console.log(\"identique après restauration : \" + (JSON.stringify(prendre()) === JSON.stringify(copie)));' '  const q = \"En une courte phrase, pourquoi prendre un instantané avant qu’un agent modifie des fichiers ?\";' '  const echantillon = \"Si les modifications tournent mal, on peut remettre chaque fichier exactement comme il était.\";' '  const r = await demander([{ role: \"user\", content: q }], echantillon, 60);' '  console.log(\"le modèle dit : \" + r.texte);' '}' 'main();' >> retour.js"

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Lancer le retour arrière

Commande
docker exec -w /home/node/project agent node retour.js

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Ce que le Run affiche

LigneCe qu’elle montre
instantané : notes.txt src/app.js src/util.jsTrois vrais fichiers dans labo-retour
changements : {"ajoutes":["nouveau.txt"],"modifies":["src/app.js"],"supprimes":["notes.txt"]}Ce qu’a fait l’agent joué par le script
identique après restauration : trueLe dossier égale de nouveau l’instantané
le modèle dit : ...Une phrase. Les mots changent à chaque exécution

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

À propos de ce labo et de sa source: Lab agent de code IA : utiliser opencode pour expliquer et corriger du code, et vérifier son travail

Vous enseignez à une classe ? Proposez ce module à vos étudiants avec un guide de l'enseignant, des devoirs corrigés et un laboratoire pour chaque étudiant.