For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
Navigation principale
Theme

Application de patchs

Permettez aux modèles de proposer des diffs structurés que votre intégration applique.

Utilisez apply_patch avec l’API Responses pour permettre au modèle de proposer la création, la modification ou la suppression de fichiers sous forme de diffs structurés. Votre application exécute chaque opération et en renvoie le résultat. Les exemples utilisent gpt-6-astra.

Quand utiliser l’outil

Vous pouvez utiliser apply_patch pour les tâches suivantes.

  • Refactorisation de plusieurs fichiers. Renommez des symboles, extrayez des fonctions utilitaires ou réorganisez des modules dans plusieurs fichiers à la fois.
  • Correction de bugs. Demandez au modèle de diagnostiquer les problèmes et de produire des patchs ciblés.
  • Génération de tests et de documentation. Créez des fichiers de test, des fixtures et de la documentation en même temps que vous modifiez le code.
  • Migrations et modifications répétitives. Appliquez des mises à jour structurées et répétitives (migrations d’API, annotations de types, corrections de mise en forme, etc.).

Si vous pouvez décrire votre dépôt et la modification souhaitée sous forme de texte, apply_patch peut généralement produire les diffs correspondants.

Utilisation de l’outil apply_patch avec l’API Responses

Pour utiliser apply_patch avec l’API Responses, procédez comme suit :

  1. Appelez l’API Responses avec l’outil apply_patch
    • Décrivez les fichiers disponibles dans input, éventuellement sous forme de résumé, ou donnez au modèle des outils pour explorer votre système de fichiers.
    • Activez l’outil avec tools=[{"type": "apply_patch"}].
  2. Laissez le modèle renvoyer une ou plusieurs opérations de patch
    • La réponse de l’API contient un ou plusieurs objets apply_patch_call.
    • Chaque appel décrit une seule opération sur un fichier : création, modification ou suppression.
  3. Appliquez les patchs dans votre environnement
    • Exécutez un harnais d’application de patchs ou un script qui effectue les tâches suivantes :
      • Interpréter le diff contenu dans operation pour chaque apply_patch_call.
      • Appliquer le patch à votre répertoire de travail ou à votre dépôt.
      • Consigner le succès ou l’échec de chaque patch, ainsi que les éventuels journaux ou messages d’erreur.
  4. Renvoyez les résultats au modèle
    • Appelez de nouveau l’API Responses en utilisant previous_response_id ou en transmettant à nouveau les éléments de la conversation dans input.
    • Incluez un événement apply_patch_call_output pour chaque call_id, avec un champ status et, si nécessaire, une chaîne output.
    • Conservez tools=[{"type": "apply_patch"}] pour que le modèle puisse poursuivre les modifications si nécessaire.
  5. Laissez le modèle poursuivre les modifications ou les expliquer
    • Le modèle peut produire d’autres opérations apply_patch_call.
    • Il peut aussi expliquer à l’utilisateur ce qu’il a modifié et pourquoi.

Exemple : renommer une fonction avec l’outil apply_patch

Étape 1 : demandez au modèle de planifier les modifications et de produire les patchs

Demandez au modèle de planifier les modifications et de produire les patchs
import OpenAI from "openai";
// Application-owned helper; see "Implementing the patch harness" in the guide.
// This demo only applies exact updates to the two in-memory files below.
import { applyOperation } from "../../support/apply-patch.mjs";

const client = new OpenAI();
const files = {
  "lib/fib.py": `def fib(n):
    if n <= 1:
        return n
    return fib(n - 1) + fib(n - 2)
`,
  "run.py": `from lib.fib import fib

print(fib(42))
`,
};
const fileContext = `The user has the following files:
<BEGIN_FILES>
${Object.entries(files)
  .map(([path, content]) => `===== ${path}\n${content}`)
  .join("\n")}
<END_FILES>

Help me rename the fib() function to fibonacci().`;

let response = await client.responses.create({
  model: "gpt-6-astra",
  input: fileContext,
  tools: [{ type: "apply_patch" }],
});

let patchCalls = response.output.filter(
  (item) => item.type === "apply_patch_call"
);

Exemple d’objet apply_patch_call

Exemple d’objet apply_patch_call
{
    "id": "apc_08f3d96c87a585390069118b594f7481a088b16cda7d9415fe",
    "type": "apply_patch_call",
    "status": "completed",
    "call_id": "call_Rjsqzz96C5xzPb0jUWJFRTNW",
    "operation": {
        "type": "update_file",
        "diff": "
@@
-def fib(n):
+def fibonacci(n):
    if n <= 1:
        return n
-    return fib(n-1) + fib(n-2)                                                  +    return fibonacci(n-1) + fibonacci(n-2),
",
        "path": "lib/fib.py"
    }
}

Étape 2 : appliquez le patch et renvoyez les résultats

Appliquez le patch et renvoyez les résultats
for (let turn = 0; patchCalls.length > 0; turn++) {
  if (turn === 8) throw new Error("Patch workflow exceeded eight tool turns.");
  const results = patchCalls.map((call) => {
    const { success, output } = applyOperation(files, call.operation);

    return {
      type: "apply_patch_call_output",
      call_id: call.call_id,
      status: success ? "completed" : "failed",
      output,
    };
  });

  response = await client.responses.create({
    model: "gpt-6-astra",
    previous_response_id: response.id,
    input: results,
    tools: [{ type: "apply_patch" }],
  });
  patchCalls = response.output.filter(
    (item) => item.type === "apply_patch_call"
  );
}

console.log(response.output_text);
for (const [path, content] of Object.entries(files)) {
  process.stdout.write(`===== ${path}\n${content}`);
}

Si l’application d’un patch échoue, par exemple parce qu’un fichier est introuvable, indiquez status: "failed" et décrivez l’erreur dans la chaîne output pour que le modèle puisse y remédier :

Signalez l’échec d’un appel à apply_patch
{
  "type": "apply_patch_call_output",
  "call_id": "call_cNWm41dB3RyQcLNOVTIPBWZU",
  "status": "failed",
  "output": "Could not apply patch to lib/foo.py — file not found on disk"
}

Opérations de l’outil apply_patch

Type d’opération Objectif Charge utile
create_file Créer un fichier à l’emplacement indiqué par path. diff est un diff au format V4A qui représente l’intégralité du contenu du fichier.
update_file Modifier le fichier existant à l’emplacement indiqué par path. diff est un diff au format V4A qui décrit des ajouts, des suppressions ou des remplacements.
delete_file Supprimer le fichier à l’emplacement indiqué par path. Aucun diff. Supprimez le fichier en entier.

Votre harnais doit interpréter les diffs au format V4A et appliquer les modifications. Pour consulter des implémentations de référence, reportez-vous au code du SDK Agents pour Python ou du SDK Agents pour TypeScript.

Implémentation du harnais d’application de patchs

Avec l’outil apply_patch, vous n’avez pas besoin de fournir de schéma d’entrée. Le modèle sait construire les objets operation. Implémentez les étapes suivantes :

  1. Analysez les opérations dans la réponse de l’API
    • Repérez dans la réponse les éléments qui contiennent type: "apply_patch_call".
    • Pour chaque appel, examinez operation.type, operation.path et, le cas échéant, diff.
  2. Exécutez les opérations sur les fichiers
    • Pour create_file et update_file, appliquez le diff V4A au système de fichiers ou à l’espace de travail en mémoire.
    • Pour delete_file, supprimez le fichier à l’emplacement indiqué par path.
    • Consignez le succès ou l’échec de chaque opération, ainsi que les éventuels journaux ou messages d’erreur.
  3. Renvoyez les événements apply_patch_call_output
    • Pour chaque call_id, renvoyez exactement un événement apply_patch_call_output avec :
      • status: "completed" si l’opération a réussi.
      • status: "failed" si une erreur s’est produite (décrivez-la brièvement et en termes clairs dans la chaîne output).

Sécurité et robustesse

  • Validation des chemins : bloquez les tentatives de traversée de répertoires et limitez les modifications aux répertoires autorisés.
  • Sauvegardes : envisagez de sauvegarder les fichiers ou de travailler sur une copie temporaire avant d’appliquer les patchs.
  • Gestion des erreurs : si un patch ne peut pas être appliqué, renvoyez systématiquement le statut failed et décrivez l’erreur dans la chaîne output.
  • Atomicité : choisissez entre une application « tout ou rien », qui annule toutes les modifications si un patch échoue, et un traitement indépendant où le succès ou l’échec se détermine fichier par fichier.

Utilisation de l’outil apply_patch avec le SDK Agents

Vous pouvez aussi utiliser l’outil apply_patch avec le SDK Agents. Vous devez toujours implémenter le harnais qui exécute les opérations sur les fichiers, mais vous pouvez confier le traitement des diffs à la fonction applyDiff.

Utilisation de l’outil apply_patch avec le SDK Agents
import {
  mkdirSync,
  realpathSync,
  lstatSync,
  readFileSync,
  writeFileSync,
  unlinkSync,
} from "node:fs";
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
import { applyDiff, Agent, run, applyPatchTool } from "@openai/agents";

class WorkspaceEditor {
  constructor(root = "workspace") {
    mkdirSync(root, { recursive: true });
    this.root = realpathSync(root);
  }

  path(name) {
    const target = resolve(this.root, name);
    const relativePath = relative(this.root, target);
    if (
      !relativePath ||
      isAbsolute(relativePath) ||
      relativePath === ".." ||
      relativePath.startsWith(`..${sep}`)
    ) {
      throw new Error("Patch paths must stay inside the workspace");
    }
    let current = this.root;
    for (const part of relativePath.split(sep)) {
      current = join(current, part);
      if (lstatSync(current, { throwIfNoEntry: false })?.isSymbolicLink()) {
        throw new Error("Patch paths must not traverse symbolic links");
      }
    }
    return target;
  }

  async createFile(operation) {
    const path = this.path(operation.path);
    const content = applyDiff("", operation.diff, "create");
    mkdirSync(dirname(path), { recursive: true });
    writeFileSync(path, content, { encoding: "utf8", flag: "wx" });
    return { status: "completed", output: `Created ${operation.path}` };
  }

  async updateFile(operation) {
    const path = this.path(operation.path);
    const content = applyDiff(readFileSync(path, "utf8"), operation.diff);
    writeFileSync(path, content, "utf8");
    return { status: "completed", output: `Updated ${operation.path}` };
  }

  async deleteFile(operation) {
    unlinkSync(this.path(operation.path));
    return { status: "completed", output: `Deleted ${operation.path}` };
  }
}

const editor = new WorkspaceEditor();

const agent = new Agent({
  name: "Patch Assistant",
  model: "gpt-6-astra",
  instructions:
    "Use apply_patch to edit files in the workspace. Supply paths relative to that workspace.",
  tools: [
    applyPatchTool({
      editor,
      // could also be a function for you to determine if approval is needed
      needsApproval: true,
      onApproval: async (_ctx, _approvalItem) => {
        // create your own approval logic
        return { approve: true };
      },
    }),
  ],
});

const result = await run(
  agent,
  "Create tasks.md with a shopping checklist of 5 entries."
);

console.log(`\nFinal response:\n${result.finalOutput}`);

Des exemples complets et exécutables sont disponibles sur GitHub.

Exemple d’utilisation d’apply_patch en TypeScript

Exemple d’utilisation de l’outil apply_patch avec le SDK Agents en TypeScript

Exemple d’utilisation d’apply_patch en Python

Exemple d’utilisation de l’outil apply_patch avec le SDK Agents en Python

Gestion des erreurs courantes

Indiquez status: "failed" et décrivez clairement l’erreur dans output pour aider le modèle à y remédier.

Erreur de fichier introuvable
{
  "type": "apply_patch_call_output",
  "call_id": "call_abc",
  "status": "failed",
  "output": "Error: File not found at path 'lib/baz.py'"
}

Le modèle peut alors adapter les diffs suivants en fonction de ces messages d’erreur, par exemple en relisant un fichier fourni dans votre prompt ou en simplifiant une modification.

Bonnes pratiques

  • Donnez au modèle les informations nécessaires sur les fichiers
    • Lorsque vous appelez l’API Responses, incluez directement une copie de vos fichiers dans la requête, comme dans l’exemple, ou donnez au modèle des outils pour explorer votre système de fichiers, comme l’outil shell.
  • Envisagez d’associer apply_patch à l’outil shell
    • Grâce à l’outil shell, le modèle peut parcourir les répertoires du système de fichiers, lire les fichiers et y rechercher des mots-clés avec grep. Il peut ainsi trouver et modifier les fichiers de manière autonome.
  • Privilégiez les diffs courts et ciblés
    • Dans vos instructions système, encouragez le modèle à limiter ses modifications au strict nécessaire et à éviter les réécritures de grande ampleur.
  • Vérifiez que les modifications s’appliquent correctement
    • Après une série de patchs, exécutez vos tests ou vos linters et signalez les erreurs dans le prochain input pour que le modèle puisse les corriger.

Notes d’utilisation