Use apply_patch com a API Responses para que o modelo proponha a criação, a atualização e a exclusão de arquivos na forma de diffs estruturados. Seu aplicativo executa cada operação e retorna o resultado ao modelo. Os exemplos usam o modelo gpt-6-astra.
Quando usar
Você pode usar apply_patch nas tarefas a seguir.
- Refatoração de vários arquivos. Renomeie símbolos, extraia funções auxiliares ou reorganize módulos em vários arquivos de uma só vez.
- Correção de bugs. Peça ao modelo que diagnostique os problemas e gere patches precisos para corrigi-los.
- Geração de testes e documentação. Crie arquivos de teste, fixtures e documentação junto com as alterações no código.
- Migrações e edições repetitivas. Aplique atualizações estruturadas e repetitivas, como migrações de API, anotações de tipo e correções de formatação.
Se você conseguir descrever em texto o repositório e a alteração desejada, a ferramenta apply_patch geralmente conseguirá gerar os diffs correspondentes.
Como usar a ferramenta apply_patch com a API Responses
Para usar apply_patch com a API Responses, siga estas etapas.
- Chame a API Responses com a ferramenta
apply_patch- Inclua informações sobre os arquivos disponíveis (ou um resumo deles) em
inputou forneça ao modelo ferramentas para explorar o sistema de arquivos. - Habilite a ferramenta com
tools=[{"type": "apply_patch"}].
- Inclua informações sobre os arquivos disponíveis (ou um resumo deles) em
- Deixe o modelo retornar uma ou mais operações de patch
- A saída da resposta inclui um ou mais objetos
apply_patch_call. - Cada chamada descreve uma única operação de criação, atualização ou exclusão de um arquivo.
- A saída da resposta inclui um ou mais objetos
- Aplique os patches no seu ambiente
- Execute um harness de patches ou um script que faça o seguinte.
- Interprete o diff de
operationpara cadaapply_patch_call. - Aplique o patch ao diretório de trabalho ou ao repositório.
- Registre se cada patch foi aplicado com sucesso e guarde os logs ou mensagens de erro, se houver.
- Interprete o diff de
- Execute um harness de patches ou um script que faça o seguinte.
- Envie os resultados dos patches ao modelo
- Chame a API Responses novamente usando
previous_response_idou reenviando os itens da conversa eminput. - Inclua um evento
apply_patch_call_outputpara cadacall_id, com o campostatuse, opcionalmente, uma string emoutput. - Mantenha
tools=[{"type": "apply_patch"}]para que o modelo possa continuar editando, se necessário.
- Chame a API Responses novamente usando
- Deixe o modelo continuar ou explicar as alterações
- O modelo pode gerar mais operações
apply_patch_callou - explicar ao usuário o que alterou e por quê.
- O modelo pode gerar mais operações
Exemplo de como renomear uma função com a ferramenta apply_patch
Etapa 1: peça ao modelo que planeje as alterações e gere os patches
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"
);Exemplo de objeto 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"
}
}Etapa 2: aplique o patch e envie os resultados ao modelo
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}`);
}Se não for possível aplicar um patch (por exemplo, porque o arquivo não foi encontrado), defina status: "failed" e inclua em output uma mensagem que ajude o modelo a corrigir o problema.
{
"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"
}Operações de patch
| Tipo de operação | Finalidade | Dados da operação |
|---|---|---|
create_file |
Cria um arquivo no caminho path. |
diff é um diff V4A que representa todo o conteúdo do arquivo. |
update_file |
Modifica um arquivo existente no caminho path. |
diff é um diff V4A com adições, exclusões ou substituições. |
delete_file |
Remove o arquivo no caminho path. |
A operação não inclui diff e exclui o arquivo por completo. |
O harness de patches interpreta o formato de diff V4A e aplica as alterações. Para consultar implementações de referência, veja o código do SDK de Agentes para Python ou do SDK de Agentes para TypeScript.
Como implementar o harness de patches
Ao usar a ferramenta apply_patch, você não precisa fornecer um schema de entrada. O modelo já sabe construir objetos operation. Sua implementação deve executar as etapas a seguir.
- Extraia as operações da resposta
- Procure na resposta os itens com
type: "apply_patch_call". - Para cada chamada, verifique
operation.type,operation.pathe, se houver,diff.
- Procure na resposta os itens com
- Execute as operações nos arquivos
- Para
create_fileeupdate_file, aplique o diff V4A ao sistema de arquivos ou ao espaço de trabalho em memória. - Para
delete_file, remova o arquivo no caminhopath. - Registre se cada operação foi concluída com sucesso e guarde os logs ou mensagens de erro, se houver.
- Para
- Retorne eventos
apply_patch_call_output- Para cada
call_id, emita exatamente um eventoapply_patch_call_outputcom o resultado da operação.- Use
status: "completed"se a operação foi concluída com sucesso. - Use
status: "failed"se ocorreu um erro e inclua emoutputuma mensagem curta e fácil de entender.
- Use
- Para cada
Segurança e robustez
- Validação de caminhos. Impeça que os caminhos apontem para fora dos diretórios permitidos e restrinja as edições a esses diretórios.
- Backups. Considere fazer backup dos arquivos ou trabalhar em uma cópia temporária antes de aplicar os patches.
- Tratamento de erros. Sempre retorne o status
failedcom uma mensagem informativa emoutputquando não for possível aplicar um patch. - Atomicidade. Decida se as operações devem seguir a regra de “tudo ou nada” (reverter todas as alterações se algum patch falhar) ou se o sucesso ou a falha de cada arquivo será independente dos demais.
Como usar a ferramenta apply_patch com o SDK de Agentes
Você também pode usar a ferramenta apply_patch com o SDK de Agentes. Ainda é preciso implementar o harness que executa as operações nos arquivos, mas você pode usar a função applyDiff para processar os diffs.
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}`);Você encontra exemplos completos e funcionais no GitHub.
Exemplo de uso da ferramenta apply_patch com o SDK de Agentes em TypeScript
Exemplo de uso da ferramenta apply_patch com o SDK de Agentes em Python
Como lidar com erros comuns
Use status: "failed" e inclua uma mensagem clara em output para ajudar o modelo a corrigir o problema.
{
"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):"
}Com base nessas mensagens de erro, o modelo pode ajustar os próximos diffs, por exemplo, relendo o conteúdo de um arquivo incluído no prompt ou simplificando uma alteração.
Boas práticas
- Dê ao modelo um contexto claro sobre os arquivos
- Ao chamar a API Responses, inclua o conteúdo atual dos arquivos diretamente na entrada, como no exemplo, ou forneça ao modelo ferramentas para explorar o sistema de arquivos, como a ferramenta
shell.
- Ao chamar a API Responses, inclua o conteúdo atual dos arquivos diretamente na entrada, como no exemplo, ou forneça ao modelo ferramentas para explorar o sistema de arquivos, como a ferramenta
- Considere usar também a ferramenta
shell- Com a ferramenta
shell, o modelo pode explorar diretórios, ler arquivos e buscar palavras-chave com grep. Assim, agentes de IA podem localizar e editar arquivos.
- Com a ferramenta
- Incentive a geração de diffs pequenos e específicos
- Nas instruções de sistema, oriente o modelo a fazer alterações mínimas e pontuais e a evitar reescritas extensas.
- Verifique se os patches foram aplicados corretamente
- Depois de aplicar uma série de patches, execute os testes ou linters e informe eventuais falhas na próxima chamada, em
input, para que o modelo possa corrigi-las.
- Depois de aplicar uma série de patches, execute os testes ou linters e informe eventuais falhas na próxima chamada, em
Observações sobre o uso
| Disponibilidade por API | Modelos compatíveis |
|---|---|