For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
Navegação principal
Theme

Aplicação de patches

Permita que os modelos proponham diffs estruturados para sua integração aplicar.

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.

  1. Chame a API Responses com a ferramenta apply_patch
    • Inclua informações sobre os arquivos disponíveis (ou um resumo deles) em input ou forneça ao modelo ferramentas para explorar o sistema de arquivos.
    • Habilite a ferramenta com tools=[{"type": "apply_patch"}].
  2. 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.
  3. Aplique os patches no seu ambiente
    • Execute um harness de patches ou um script que faça o seguinte.
      • Interprete o diff de operation para cada apply_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.
  4. Envie os resultados dos patches ao modelo
    • Chame a API Responses novamente usando previous_response_id ou reenviando os itens da conversa em input.
    • Inclua um evento apply_patch_call_output para cada call_id, com o campo status e, opcionalmente, uma string em output.
    • Mantenha tools=[{"type": "apply_patch"}] para que o modelo possa continuar editando, se necessário.
  5. Deixe o modelo continuar ou explicar as alterações
    • O modelo pode gerar mais operações apply_patch_call ou
    • explicar ao usuário o que alterou e por quê.

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

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

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

Aplique o patch e retorne os resultados
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.

Informe a falha de uma chamada 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"
}

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.

  1. Extraia as operações da resposta
    • Procure na resposta os itens com type: "apply_patch_call".
    • Para cada chamada, verifique operation.type, operation.path e, se houver, diff.
  2. Execute as operações nos arquivos
    • Para create_file e update_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 caminho path.
    • Registre se cada operação foi concluída com sucesso e guarde os logs ou mensagens de erro, se houver.
  3. Retorne eventos apply_patch_call_output
    • Para cada call_id, emita exatamente um evento apply_patch_call_output com 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 em output uma mensagem curta e fácil de entender.

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 failed com uma mensagem informativa em output quando 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.

Use a ferramenta apply_patch com o SDK de Agentes
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 da ferramenta apply_patch em TypeScript

Exemplo de uso da ferramenta apply_patch com o SDK de Agentes em TypeScript

Exemplo da ferramenta apply_patch em Python

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.

Erro de arquivo não encontrado
{
  "type": "apply_patch_call_output",
  "call_id": "call_abc",
  "status": "failed",
  "output": "Error: File not found at path 'lib/baz.py'"
}

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.
  • 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.
  • 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.

Observações sobre o uso