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

Shell local

Permita que agentes executem comandos em um shell local.

A ferramenta de shell local está desatualizada. Para novos casos de uso, use a ferramenta shell com GPT-5.1. Saiba mais.

Shell local é uma ferramenta que permite aos agentes executar comandos de shell localmente em uma máquina fornecida por você ou pelo usuário. Ela foi projetada para funcionar com o Codex CLI e o codex-mini-latest. Os comandos são executados no seu próprio ambiente de execução, portanto você tem controle total sobre quais comandos são realmente executados. A API apenas retorna instruções; ela não as executa na infraestrutura da OpenAI.

O shell local está disponível pela Responses API para uso com o codex-mini-latest. Ele não está disponível em outros modelos nem pela API chat completions.

Executar comandos de shell arbitrários pode ser perigoso. Sempre execute em um ambiente isolado ou adicione listas rigorosas de permissões ou de bloqueios antes de encaminhar um comando ao shell do sistema.


Consulte o Codex CLI para ver uma implementação de referência.

Como funciona

A ferramenta de shell local permite que os agentes operem em um ciclo contínuo com acesso a um terminal.

O modelo envia comandos de shell, que seu código executa em uma máquina local antes de retornar a saída ao modelo. Esse ciclo permite que o modelo conclua o ciclo de compilação, teste e execução sem intervenção adicional do usuário.

Seu código deve implementar um ciclo que aguarde itens de saída local_shell_call e execute os comandos que eles contêm. Recomendamos fortemente usar um ambiente isolado para evitar a execução de comandos inesperados.

Integração da ferramenta de shell local

Estas são as etapas gerais que você precisa seguir para integrar a ferramenta de shell local ao seu aplicativo:

  1. Envie uma solicitação ao modelo: Inclua a ferramenta local_shell entre as ferramentas disponíveis.

  2. Receba uma resposta do modelo: Verifique se a resposta contém itens local_shell_call. Essa chamada de ferramenta contém uma ação, como exec, com um comando a ser executado.

  3. Execute a ação solicitada: Execute o comando no ambiente local que você controla.

  4. Retorne a saída da ação: Após executar a ação, retorne a saída do comando ao modelo.

  5. Repita: Envie uma nova solicitação com o estado atualizado como um local_shell_call_output e repita esse ciclo até que o modelo pare de solicitar ações ou você decida parar.

Exemplo de fluxo de trabalho

Abaixo está um exemplo mínimo que demonstra o ciclo de solicitação e resposta. Escolha uma linguagem para ver o fluxo de trabalho equivalente com o SDK correspondente. Para manter o exemplo breve, foram omitidos o isolamento da execução e as verificações de segurança adequados para produção. Não execute comandos não confiáveis em produção sem proteções adicionais.

import { spawn } from "node:child_process";
import process from "node:process";
import OpenAI from "openai";

const client = new OpenAI();
const MAX_TIMEOUT_MS = 10_000;

function runCommand(command, options) {
  return new Promise((resolve) => {
    let stdout = "";
    let stderr = "";
    let settled = false;
    let groupPoll;
    const child = spawn(command[0], command.slice(1), {
      ...options,
      detached: process.platform !== "win32",
      stdio: ["ignore", "pipe", "pipe"],
    });
    const finish = (suffix = "") => {
      if (settled) return;
      settled = true;
      clearTimeout(timer);
      clearTimeout(groupPoll);
      resolve(stdout + stderr + suffix);
    };
    const processGroupIsRunning = () => {
      if (process.platform === "win32" || !child.pid) return false;
      try {
        process.kill(-child.pid, 0);
        return true;
      } catch {
        return false;
      }
    };
    const finishAfterProcessGroup = (suffix) => {
      if (settled) return;
      if (processGroupIsRunning()) {
        groupPoll = setTimeout(() => finishAfterProcessGroup(suffix), 10);
      } else {
        finish(suffix);
      }
    };
    const killProcessTree = () => {
      try {
        if (process.platform !== "win32" && child.pid) {
          process.kill(-child.pid, "SIGKILL");
        } else {
          child.kill("SIGKILL");
        }
      } catch {
        child.kill("SIGKILL");
      }
      child.stdout?.destroy();
      child.stderr?.destroy();
    };
    const timer = setTimeout(() => {
      killProcessTree();
      finish("Command timed out.\n");
    }, options.timeout);

    child.stdout?.on("data", (chunk) => {
      stdout += chunk;
    });
    child.stderr?.on("data", (chunk) => {
      stderr += chunk;
    });
    child.on("error", (error) => {
      finish(`Command failed: ${error.message}.\n`);
    });
    child.on("close", (code, signal) => {
      if (signal) {
        finishAfterProcessGroup(`Command failed with signal ${signal}.\n`);
      } else if (code !== 0) {
        finishAfterProcessGroup(`Command failed with exit code ${code}.\n`);
      } else {
        finishAfterProcessGroup("");
      }
    });
  });
}

let response = await client.responses.create({
  model: "codex-mini-latest",
  tools: [{ type: "local_shell" }],
  parallel_tool_calls: false,
  input: "List files in the current directory.",
});

while (true) {
  const shellCall = response.output.find(
    (item) => item.type === "local_shell_call"
  );
  if (!shellCall) break;

  const { command, env, timeout_ms, user, working_directory } =
    shellCall.action;
  let output;
  if (user) {
    output = `Unsupported execution user: ${user}.\n`;
  } else if (command.length === 0) {
    output = "Command is empty.\n";
  } else {
    const timeout =
      timeout_ms && timeout_ms > 0
        ? Math.min(timeout_ms, MAX_TIMEOUT_MS)
        : MAX_TIMEOUT_MS;
    try {
      output = await runCommand(command, {
        cwd: working_directory ?? process.cwd(),
        env: { PATH: process.env.PATH ?? "", ...env },
        timeout,
      });
    } catch (error) {
      output = `Command failed: ${error instanceof Error ? error.message : String(error)}.\n`;
    }
  }

  response = await client.responses.create({
    model: "codex-mini-latest",
    tools: [{ type: "local_shell" }],
    parallel_tool_calls: false,
    previous_response_id: response.id,
    input: [
      {
        type: "local_shell_call_output",
        id: shellCall.call_id,
        output,
      },
    ],
  });
}

console.log(response.output_text);

Práticas recomendadas

  • Use um ambiente isolado ou um contêiner para a execução. Considere usar Docker ou uma conta de usuário confinada.
  • Imponha limites de recursos (tempo, memória, rede). O timeout_ms fornecido pelo modelo é apenas uma sugestão; você deve aplicar seus próprios limites.
  • Filtre ou examine com cuidado comandos de alto risco (por exemplo, rm, curl, utilitários de rede).
  • Registre cada comando e sua saída para auditoria e depuração.

Tratamento de erros

Se o comando falhar no seu ambiente, por exemplo, com um código de saída diferente de zero ou por exceder o tempo limite, você ainda poderá enviar um local_shell_call_output; inclua a mensagem de erro no campo output.

O modelo pode optar por se recuperar da falha ou tentar executar um comando diferente. Se você enviar dados malformados (por exemplo, sem id), a API retornará um erro de validação padrão 400.