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 :
- 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"}].
- Décrivez les fichiers disponibles dans
- 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.
- La réponse de l’API contient un ou plusieurs objets
- 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
operationpour chaqueapply_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.
- Interpréter le diff contenu dans
- Exécutez un harnais d’application de patchs ou un script qui effectue les tâches suivantes :
- Renvoyez les résultats au modèle
- Appelez de nouveau l’API Responses en utilisant
previous_response_idou en transmettant à nouveau les éléments de la conversation dansinput. - Incluez un événement
apply_patch_call_outputpour chaquecall_id, avec un champstatuset, si nécessaire, une chaîneoutput. - Conservez
tools=[{"type": "apply_patch"}]pour que le modèle puisse poursuivre les modifications si nécessaire.
- Appelez de nouveau l’API Responses en utilisant
- 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.
- Le modèle peut produire d’autres opérations
Exemple : renommer une fonction avec l’outil apply_patch
Étape 1 : 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
{
"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
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 :
{
"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 :
- 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.pathet, le cas échéant,diff.
- Repérez dans la réponse les éléments qui contiennent
- Exécutez les opérations sur les fichiers
- Pour
create_fileetupdate_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é parpath. - Consignez le succès ou l’échec de chaque opération, ainsi que les éventuels journaux ou messages d’erreur.
- Pour
- Renvoyez les événements
apply_patch_call_output- Pour chaque
call_id, renvoyez exactement un événementapply_patch_call_outputavec :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îneoutput).
- Pour chaque
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
failedet décrivez l’erreur dans la chaîneoutput. - 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.
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 de l’outil apply_patch avec le SDK Agents en TypeScript
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.
{
"type": "apply_patch_call_output",
"call_id": "call_abc",
"status": "failed",
"output": "Error: File not found at path 'lib/baz.py'"
}{
"type": "apply_patch_call_output",
"call_id": "call_abc",
"status": "failed",
"output": "Error: Invalid Context:\n@@ def fib(n):"
}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.
- 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
- 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.
- Grâce à l’outil
- 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
inputpour que le modèle puisse les corriger.
- Après une série de patchs, exécutez vos tests ou vos linters et signalez les erreurs dans le prochain
Notes d’utilisation
| Disponibilité par API | Modèles compatibles |
|---|---|