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

Uso do computador

Permita que um agente conclua tarefas em um navegador hospedado pela OpenAI.

Com o Uso do computador, um agente pode navegar por sites e interagir com interfaces no navegador para testar um site, coletar informações ou usar um aplicativo pela interface gráfica.

A API de Agentes executa o navegador em um ambiente hospedado pela OpenAI. Seu aplicativo inicia a sessão e acompanha os eventos. O agente decide o que fazer em seguida com base no que observa no navegador.

Para executar uma tarefa no navegador:

  1. Crie uma sessão do navegador e salve o ID da sessão.
  2. Acompanhe os eventos da sessão e envie uma tarefa ao agente.
  3. Responda a cada solicitação de acesso a um site. Se a tarefa exigir uma conta, gerencie o login.
  4. Aguarde o fim do turno do agente principal e verifique o resultado. Se a conexão cair, recupere a mesma sessão antes de tentar novamente.
  5. Revise a atividade salva do navegador e exclua a sessão quando terminar.

Configure o navegador

Siga os pré-requisitos do guia de início rápido da API de Agentes para criar uma chave de API e exportar OPENAI_API_KEY. Em seguida, instale o SDK da OpenAI para sua linguagem. Para os exemplos em JavaScript, instale openai e prompt-sync. Os exemplos com cURL exigem Bash e jq.

Para habilitar o acesso ao navegador:

  • Adicione { "type": "computer_use" } a agent.tools.
  • Defina environment.type como openai_hosted e environment.desktop.enabled como true.

Nos exemplos em JavaScript a seguir, você cria uma sessão, gerencia as aprovações de acesso a sites e, em seguida, envia uma tarefa e imprime a resposta. Comece criando uma sessão do navegador com as capturas de tela habilitadas. Isso não inicia uma tarefa.

Crie uma sessão do navegador
import OpenAI from "openai";
import { open } from "node:fs/promises";

const client = new OpenAI();
const session = await client.beta.agents.sessions.create({
  agent: {
    model: "gpt-6-astra",
    instructions:
      "Read public documentation in the browser. Do not sign in or change any website data. Report the page title and URL you find.",
    tools: [{ type: "computer_use", include_screenshots: true }],
  },
  environment: {
    type: "openai_hosted",
    desktop: { enabled: true },
    network: { access: "enabled" },
  },
});
console.log("Session ID:", session.id);

Gerencie o acesso a origens

O navegador exige a aprovação do usuário antes de acessar cada nova origem, inclusive em sites públicos. Habilitar o acesso à rede não aprova essas solicitações.

Mesmo com a revisão automática habilitada, o navegador continua solicitando aprovação para acessar novas origens e enviando solicitações de login. Continue processando os dois tipos de solicitação no aplicativo.

Para processar uma solicitação de aprovação de acesso a uma origem:

  1. Ao receber agent.session.requires_action, consulte a sessão e verifique a lista atual de required_actions.
  2. Localize as entradas pendentes do tipo computer_use_approval_request cujo campo aninhado request.type seja browser_origin_access.
  3. Mostre a origem solicitada (origin) e o motivo (reason), se informado. Peça ao usuário que escolha entre approve, deny e cancel. Envie a decisão pelo endpoint de eventos da sessão com o mesmo request_id e um objeto response aninhado que contenha type: "browser_origin_access" e decision, como no exemplo abaixo.
A aprovação de acesso a uma origem não exige confirmação antes de cada ação

Se o aplicativo precisar garantir que o usuário confirme compras, alterações destrutivas ou outras ações de impacto antes da execução, limite o acesso do navegador hospedado a recursos que não permitam essas ações ou use um ambiente de execução do navegador que você controle. Se você usar uma ferramenta de função para pedir confirmação, o pedido dependerá de o agente chamar essa função.

Trate o conteúdo dos sites como não confiável. Ele não pode conceder permissões nem substituir as instruções do usuário. Consulte as orientações sobre confirmação e consentimento em um ambiente de execução que você controla.

Defina esta função auxiliar antes do código da tarefa. Ela processa as aprovações de acesso a origens e cancela as solicitações de login porque a tarefa só consulta páginas públicas.

Responda às solicitações de acesso a origens
import { createInterface } from "node:readline";

const inputLines = createInterface({
  input: process.stdin,
  crlfDelay: Infinity,
});
const answers = inputLines[Symbol.asyncIterator]();

/** @param {OpenAI} client */
async function respondToOriginApproval(client, sessionId, approval) {
  const request = approval.request;
  if (request.type === "browser_origin_access") {
    console.log("Requested origin:", request.origin);
    console.log(request.reason ?? "The browser needs access to this origin.");
    let input;
    do {
      process.stdout.write(
        "Allow access? [approve/deny/cancel, default deny] "
      );
      const answer = await answers.next();
      input = (answer.done ? "" : answer.value).trim().toLowerCase() || "deny";
    } while (!["approve", "deny", "cancel"].includes(input));
    const decision =
      input === "approve" ? "approve" : input === "cancel" ? "cancel" : "deny";
    await client.beta.agents.sessions.events.create(sessionId, {
      events: [
        {
          type: "agent.session.input.computer_use_approval_request_result",
          request_id: approval.request_id,
          response: { type: "browser_origin_access", decision },
        },
      ],
    });
  } else if (request.type === "browser_authentication") {
    // This public-page task must not sign in.
    await client.beta.agents.sessions.events.create(sessionId, {
      events: [
        {
          type: "agent.session.input.computer_use_approval_request_result",
          request_id: approval.request_id,
          response: { type: "browser_authentication", action: "cancel" },
        },
      ],
    });
  } else {
    throw new Error(`Unsupported approval request: ${request.type}`);
  }
}

Mantenha o fluxo de eventos aberto e processe todas as aprovações pendentes. Use request_id para acompanhar as solicitações e remova os controles de aprovação quando uma solicitação deixar de constar em required_actions da sessão. Cancelar uma solicitação de aprovação não cancela a tarefa.

Uma resposta 202 indica que a decisão foi aceita. A navegação ainda pode estar em andamento.

Execute uma tarefa no navegador

Peça ao agente que encontre o guia de início rápido da API de Agentes no site público para desenvolvedores e informe o título e a URL do guia.

Abra o fluxo de eventos antes de enviar a tarefa para que o aplicativo receba os primeiros eventos de progresso. Processe as aprovações de acesso a origens à medida que as solicitações chegarem para que o navegador possa prosseguir.

Envie a tarefa e acompanhe o resultado
let screenshot;
const events = await client.beta.agents.sessions.events.stream(session.id);
const handledRequests = new Set();
let completed = false;
try {
  await client.beta.agents.sessions.events.create(session.id, {
    events: [
      {
        type: "agent.session.input.message",
        input: [
          {
            role: "user",
            content: [
              {
                type: "input_text",
                text: "Open https://developers.openai.com in the browser. Find the Agents API quickstart, then report its page title and URL.",
              },
            ],
          },
        ],
      },
    ],
  });
  for await (const event of events) {
    switch (event.type) {
      case "agent.session.requires_action": {
        const current = await client.beta.agents.sessions.retrieve(
          session.id
        );
        for (const approval of current.required_actions) {
          if (
            approval.type === "computer_use_approval_request" &&
            !handledRequests.has(approval.request_id)
          ) {
            await respondToOriginApproval(client, session.id, approval);
            handledRequests.add(approval.request_id);
          }
        }
        break;
      }
      case "agent.session.turn.item.done": {
        // Preserve streamed screenshots; retrieved history may omit image bytes.
        const item = event.item;
        if (item.type === "computer_use_call") {
          const output = item.output;
          if (
            output?.type === "computer_screenshot" &&
            output.image_url.startsWith("data:image/jpeg;base64,")
          ) {
            screenshot = Buffer.from(
              output.image_url.split(",", 2)[1],
              "base64"
            );
          }
        }
        break;
      }
      case "agent.session.turn.output_text.done":
        console.log(event.text);
        break;
      case "error":
        throw new Error(event.error.message);
      case "agent.session.failed":
      case "agent.session.environment.failed":
        throw new Error(`Agent lifecycle failure: ${event.type}`);
      case "agent.session.turn.failed":
        if (event.turn.subagent_id === null) {
          throw new Error(event.turn.error?.message ?? "Browser task failed");
        }
        break;
      case "agent.session.turn.cancelled":
        if (event.turn.subagent_id === null) {
          throw new Error("Browser task was cancelled");
        }
        break;
      case "agent.session.turn.completed":
        if (event.turn.subagent_id === null) completed = true;
        break;
    }
    if (completed) break;
  }
  if (!completed) {
    throw new Error("Stream closed before the browser task finished");
  }
  console.log();
} finally {
  events.controller.abort();
}

O exemplo imprime a resposta do agente. Verifique se ela contém o título e a URL do guia de início rápido.

Fechar o fluxo de eventos não interrompe a tarefa. Para interrompê-la, cancele o turno. Em caso de falha na conexão ou de dúvida sobre o resultado, siga as orientações de recuperação. O exemplo detalhado com cURL inclui diagnósticos de transporte e de erros.

Acompanhe a atividade do navegador

As operações do navegador aparecem como itens computer_use_call na saída da sessão. Os itens têm a mesma estrutura no fluxo de eventos e no histórico salvo da sessão.

Campo Significado
id Identificador do item de atividade.
turn_id Turno que gerou a atividade.
title Descrição da atividade do navegador ou null.
status in_progress, completed, failed ou incomplete.
output Captura de tela retornada, quando disponível.

Use o título e o status para mostrar o progresso no aplicativo. Um item de atividade do navegador descreve uma operação da ferramenta. Ele não contém a resposta final do agente nem indica se o turno inteiro foi concluído. Consulte Eventos e itens para conhecer o modelo de eventos da sessão.

Inclua capturas de tela

Para mostrar o progresso do navegador no aplicativo, defina include_screenshots como true na ferramenta computer_use. Por padrão, a API não inclui capturas de tela na saída, mas o agente continua podendo visualizá-las.

O evento de conclusão de uma atividade do navegador inclui em item.output a última captura de tela emitida pela atividade, quando disponível:

{
  "type": "computer_screenshot",
  "image_url": "data:image/jpeg;base64,..."
}

Use image_url para exibir a captura de tela. Algumas operações retornam output: null mesmo com as capturas de tela habilitadas. Por isso, o aplicativo deve lidar com itens de atividade sem imagem.

As capturas de tela podem conter dados sensíveis da página ou da conta. Mostre-as apenas a usuários autorizados e não as inclua nos logs do aplicativo.

Ao consumir o fluxo, armazene as capturas de tela disponíveis nos eventos agent.session.turn.item.done. O histórico recuperado pode omitir os bytes da imagem. Guarde a imagem no aplicativo para não depender de uma solicitação posterior de listagem de itens. Após o fim do turno, os exemplos dos SDKs listam a atividade do navegador e salvam a captura de tela mais recente. A maioria usa browser-screenshot.jpg. O exemplo em Java usa um arquivo temporário.

Consulte a atividade do navegador
for await (const item of client.beta.agents.sessions.items.list(session.id, {
  order: "asc",
  limit: 100,
})) {
  if (item.type !== "computer_use_call") continue;
  console.log(item.title ?? "Browser activity", item.status);
}
if (screenshot) {
  const file = await open("browser-screenshot.jpg", "wx", 0o600);
  try {
    await file.writeFile(screenshot);
  } finally {
    await file.close();
  }
  console.log("Saved browser-screenshot.jpg");
} else {
  console.log("No browser screenshot was returned.");
}

Os exemplos dos SDKs não sobrescrevem arquivos existentes. Mova ou remova browser-screenshot.jpg antes de executá-los novamente.

Gerencie o login

Tarefas como consultar issues em um repositório privado do GitHub exigem uma sessão autenticada no navegador. Seu aplicativo gerencia o login para que os usuários possam escolher um método de login e inserir as credenciais fora do chat.

O login pode envolver várias solicitações. Por exemplo, um site pode pedir ao usuário que escolha o login por e-mail, informe o endereço de e-mail e, em seguida, insira um código de verificação. Monte a interface com base nos métodos de login e nos campos de cada solicitação.

Apenas o agente principal pode solicitar autenticação no navegador. Os subagentes não podem fazer essa solicitação. Esse fluxo aceita endereços de e-mail, senhas e códigos de verificação, mas não oferece suporte a chaves de acesso nem a login por código QR. Se o site exigir um método sem suporte, não será possível concluir o login por esse fluxo.

Mantenha aberto o fluxo de eventos da tarefa e processe as aprovações de acesso a origens à medida que as solicitações chegarem. Ao receber agent.session.requires_action, consulte a sessão e procure, na lista atual de required_actions, entradas do tipo computer_use_approval_request cujo campo aninhado request.type seja browser_authentication.

Use o objeto request aninhado para montar a interface de login:

Campo Como usar
reason Se houver um motivo, mostre por que é preciso fornecer os dados. O valor pode ser null.
credential_origin Mostre o destino das credenciais. O valor pode ser null.
fields Monte os campos de entrada com base nos valores de id, label, type e required de cada campo. A lista pode estar vazia.
options Mostre os métodos de login disponíveis. Cada opção tem um id, um label e uma lista field_ids que identifica seus campos de entrada.

Se a solicitação oferecer métodos de login, deixe o usuário escolher um deles e mostre os campos correspondentes. Caso contrário, mostre diretamente os campos da solicitação.

Peça aos usuários que insiram credenciais apenas para um destino que possam verificar. Se a origem das credenciais estiver ausente ou for desconhecida e o usuário não puder verificá-la por outro meio, cancele a solicitação de autenticação.

Envie os dados informados pelo usuário usando o request_id do objeto de ação que contém a solicitação ou cancele a solicitação de autenticação se o usuário recusar. Continue processando as solicitações à medida que chegarem. O envio de uma resposta não confirma que o login foi bem-sucedido. Acompanhe a tarefa até o fim e verifique o resultado.

Exemplo: escolha um método e insira um código

Um site que oferece login por código enviado por e-mail ou por senha pode primeiro pedir ao usuário que escolha um método, sem solicitar o preenchimento de campos:

Escolha um método de login
{
  "type": "computer_use_approval_request",
  "turn_id": "turn_example",
  "request_id": "request_choose_method",
  "request": {
    "type": "browser_authentication",
    "reason": "Choose how to sign in to the issue tracker",
    "credential_origin": "https://issues.example.com",
    "fields": [],
    "options": [
      { "id": "email_code", "label": "Email me a code", "field_ids": [] },
      { "id": "password", "label": "Use a password", "field_ids": [] }
    ]
  }
}

Se o usuário escolher o login por código enviado por e-mail, envie selected_option: "email_code" com fields: [] usando o request_id dessa solicitação. O site poderá então pedir o endereço de e-mail e o código de verificação em solicitações separadas. Monte a interface de cada nova solicitação com os campos e IDs da própria solicitação. Inclua selected_option apenas quando ela oferecer opções.

Envie os dados informados pelo usuário

Quando o usuário terminar de preencher uma solicitação de login, envie a resposta pelo endpoint de eventos da sessão. Defina action como submit e use os IDs da solicitação e dos campos que constam na aprovação pendente. Veja um exemplo de resposta a uma solicitação de endereço de e-mail:

{
  "events": [
    {
      "type": "agent.session.input.computer_use_approval_request_result",
      "request_id": "REQUEST_ID",
      "response": {
        "type": "browser_authentication",
        "action": "submit",
        "fields": [{ "field_id": "email", "value": "USER_ENTERED_VALUE" }]
      }
    }
  ]
}

Se a solicitação oferecer métodos de login, inclua o ID do método escolhido em response.selected_option. Envie apenas os campos listados em field_ids desse método, com um valor não vazio para cada campo obrigatório. Se o método não tiver campos, envie fields: [].

Se a solicitação não oferecer métodos de login, omita selected_option e envie diretamente os campos da solicitação. Quando a solicitação listar campos, inclua pelo menos um, mesmo que todos sejam opcionais.

Envie os dados de login apenas por esse evento dedicado. Os valores enviados ficam fora da entrada do modelo do agente e não aparecem nos itens de resposta de autenticação no histórico da sessão.

Trate todos os valores como dados sensíveis, inclusive os endereços de e-mail. Oculte os valores digitados, não os inclua em logs, dados de análise ou no estado salvo da interface e limpe o formulário após o envio. Não envie credenciais em mensagens comuns nem nos resultados de ferramentas de função.

Omita turn_id do evento de envio. Consulte os limites de envio de dados de autenticação para conhecer as restrições dos campos e do conteúdo enviado.

Uma resposta 202 com corpo vazio confirma que os dados enviados foram aceitos. Ela não confirma o sucesso do login. Continue acompanhando os eventos da sessão para identificar novas solicitações ou a retomada da tarefa. Desative as novas tentativas automáticas no cliente HTTP ou no SDK ao enviar credenciais. Se não tiver certeza de que os dados foram aceitos, consulte a sessão novamente antes de continuar.

Permita que o usuário cancele

Se o usuário optar por não fazer login, responda à solicitação pendente com action: "cancel". Use o request_id dessa solicitação e omita fields e selected_option:

{
  "events": [
    {
      "type": "agent.session.input.computer_use_approval_request_result",
      "request_id": "REQUEST_ID",
      "response": { "type": "browser_authentication", "action": "cancel" }
    }
  ]
}

Isso cancela a solicitação de autenticação. Para interromper a tarefa, cancele o turno.

Execute uma tarefa em um navegador autenticado

Seu aplicativo processa as aprovações de acesso a origens e as solicitações de login enquanto acompanha os eventos da sessão. Defina a função auxiliar abaixo antes de executar a tarefa. Ela mostra o destino, oculta os valores enquanto o usuário os digita e envia a resposta. Se o usuário recusar, a função cancela a solicitação de login.

Gerencie as aprovações e o login no navegador
import promptSync from "prompt-sync";

const prompt = promptSync({ sigint: true });

/** @param {OpenAI} client */
async function respondToComputerUseApproval(client, sessionId, approval) {
  const request = approval.request;
  if (request.type === "browser_origin_access") {
    console.log("Requested origin:", request.origin);
    console.log(request.reason ?? "The browser needs access to this origin.");
    let input;
    do {
      input =
        prompt("Allow access? [approve/deny/cancel, default deny] ")
          .trim()
          .toLowerCase() || "deny";
    } while (!["approve", "deny", "cancel"].includes(input));
    const decision =
      input === "approve" ? "approve" : input === "cancel" ? "cancel" : "deny";
    await client.beta.agents.sessions.events.create(sessionId, {
      events: [
        {
          type: "agent.session.input.computer_use_approval_request_result",
          request_id: approval.request_id,
          response: { type: "browser_origin_access", decision },
        },
      ],
    });
    return;
  }
  if (request.type !== "browser_authentication") {
    throw new Error(`Unsupported approval request: ${request.type}`);
  }
  async function cancelSignIn() {
    await client.beta.agents.sessions.events.create(
      sessionId,
      {
        events: [
          {
            type: "agent.session.input.computer_use_approval_request_result",
            request_id: approval.request_id,
            response: { type: "browser_authentication", action: "cancel" },
          },
        ],
      },
      { maxRetries: 0 }
    );
  }
  console.log(request.reason ?? "Sign in to continue");
  console.log(
    "Credential origin:",
    request.credential_origin ?? "Not supplied"
  );
  const consent = prompt("Have you verified the sign-in destination? [y/N] ")
    .trim()
    .toLowerCase();
  if (!["y", "yes"].includes(consent)) {
    await cancelSignIn();
    return;
  }

  let selectedOption;
  let activeFields = request.fields;
  if (request.options.length > 0) {
    request.options.forEach((option, index) => {
      console.log(`${index + 1}. ${option.label}`);
    });
    let choice;
    do {
      const input = prompt("Choose a sign-in method, or enter cancel: ")
        .trim()
        .toLowerCase();
      if (input === "cancel") {
        await cancelSignIn();
        return;
      }
      choice = Number(input);
    } while (
      !Number.isInteger(choice) ||
      choice < 1 ||
      choice > request.options.length
    );
    selectedOption = request.options[choice - 1];
    activeFields = request.fields.filter((field) =>
      selectedOption.field_ids.includes(field.id)
    );
  }

  const fields = [];
  do {
    for (const field of activeFields) {
      while (true) {
        const value = prompt.hide(
          `${field.label}${field.required ? "" : " (optional)"} (leave blank for options): `
        );
        if (value.length > 0) {
          fields.push({ field_id: field.id, value });
          break;
        }
        let action;
        do {
          action = prompt(
            field.required
              ? "Enter a value or cancel sign-in? [enter/cancel, default enter] "
              : "Skip this field, enter a value, or cancel sign-in? [skip/enter/cancel, default skip] "
          )
            .trim()
            .toLowerCase();
        } while (
          ![
            "",
            "enter",
            "cancel",
            ...(field.required ? [] : ["skip"]),
          ].includes(action)
        );
        if (action === "cancel") {
          await cancelSignIn();
          return;
        }
        if (!field.required && (action === "" || action === "skip")) break;
      }
    }
    if (!selectedOption && activeFields.length > 0 && fields.length === 0) {
      console.log(
        "This form requires at least one field. Enter a value or cancel sign-in."
      );
    }
  } while (!selectedOption && activeFields.length > 0 && fields.length === 0);
  await client.beta.agents.sessions.events.create(
    sessionId,
    {
      events: [
        {
          type: "agent.session.input.computer_use_approval_request_result",
          request_id: approval.request_id,
          response: {
            type: "browser_authentication",
            action: "submit",
            fields,
            ...(selectedOption ? { selected_option: selectedOption.id } : {}),
          },
        },
      ],
    },
    { maxRetries: 0 }
  );
}

O exemplo a seguir pede ao agente que consulte as issues de um repositório privado do GitHub. Substitua https://github.com/acme/private-repo/issues pela URL de uma página de issues à qual você tenha acesso.

Abra o fluxo de eventos antes de enviar a tarefa e chame a função auxiliar sempre que a sessão solicitar dados.

Consulte as issues de um repositório privado
import OpenAI from "openai";

const client = new OpenAI();
const session = await client.beta.agents.sessions.create({
  agent: {
    model: "gpt-6-astra",
    instructions:
      "Read the requested GitHub issue list in the browser. Request sign-in when needed. Do not create, edit, comment on, or close issues.",
    tools: [{ type: "computer_use", include_screenshots: false }],
  },
  environment: {
    type: "openai_hosted",
    desktop: { enabled: true },
    network: { access: "enabled" },
  },
});
console.log("Session ID:", session.id);

let completed = false;
let readyToDelete = false;
try {
  const events = await client.beta.agents.sessions.events.stream(session.id);
  const handledRequests = new Set();
  try {
    await client.beta.agents.sessions.events.create(session.id, {
      events: [
        {
          type: "agent.session.input.message",
          input: [
            {
              role: "user",
              content: [
                {
                  type: "input_text",
                  // Replace this illustrative URL with your private repository.
                  text: "Open https://github.com/acme/private-repo/issues in the browser. Sign in if needed, then report the title and URL of the most recently updated open issue. Do not make changes.",
                },
              ],
            },
          ],
        },
      ],
    });
    for await (const event of events) {
      switch (event.type) {
        case "agent.session.requires_action": {
          const current = await client.beta.agents.sessions.retrieve(
            session.id
          );
          for (const approval of current.required_actions) {
            if (
              approval.type === "computer_use_approval_request" &&
              !handledRequests.has(approval.request_id)
            ) {
              await respondToComputerUseApproval(client, session.id, approval);
              handledRequests.add(approval.request_id);
            }
          }
          break;
        }
        case "agent.session.turn.output_text.done":
          console.log(event.text);
          break;
        case "error":
          throw new Error(event.error.message);
        case "agent.session.failed":
        case "agent.session.environment.failed":
          throw new Error(`Agent lifecycle failure: ${event.type}`);
        case "agent.session.turn.failed":
          if (event.turn.subagent_id === null) {
            throw new Error(event.turn.error?.message ?? "Browser task failed");
          }
          break;
        case "agent.session.turn.cancelled":
          if (event.turn.subagent_id === null) {
            throw new Error("Browser task was cancelled");
          }
          break;
        case "agent.session.turn.completed":
          if (event.turn.subagent_id === null) completed = true;
          break;
      }
      if (completed) break;
    }
    if (!completed) {
      throw new Error("Stream closed before the browser task finished");
    }
    console.log();
  } finally {
    events.controller.abort();
  }
  readyToDelete = completed;
} catch (error) {
  console.error(
    `Session ${session.id} was kept. Use the same ID to check its status before trying again.`
  );
  throw error;
} finally {
  if (readyToDelete) await client.beta.agents.sessions.delete(session.id);
}

O login pode exigir várias solicitações. Continue processando as aprovações até o fim da tarefa. Verifique se o resultado do agente corresponde ao que foi solicitado. Neste exemplo, confira o título e a URL da issue informados pelo agente.

Consulte o histórico de login

As solicitações de autenticação e as respostas aceitas aparecem no histórico da sessão e nos eventos agent.session.turn.item.added. Os itens de solicitação contêm os metadados do formulário de login. Os itens de resposta registram a ação aceita sem incluir os valores das credenciais enviadas.

Use o histórico para revisar interações anteriores. Para saber se um formulário de login ainda aguarda dados, consulte a lista atual de required_actions da sessão. Uma resposta registrada não confirma que o login foi bem-sucedido.

As aprovações de acesso a origens não têm itens de solicitação ou resposta dedicados no histórico. Processe essas aprovações por meio de required_actions.

Faça uma pergunta ao usuário

Para pedir esclarecimentos ou permitir que o usuário faça uma escolha durante a tarefa, defina uma ferramenta de função em agent.tools. Por exemplo, você pode definir request_user_response para exibir uma pergunta e coletar a resposta. Seu aplicativo fornece o nome da ferramenta, o schema dos argumentos e a interface.

Ao receber agent.session.requires_action, localize a function_call pendente da ferramenta e use seus arguments para exibir a pergunta. Retorne a resposta por meio de agent.session.input.tool_result, usando o turn_id e o call_id da ação. Defina success: true e insira a resposta em output. Para respostas estruturadas, serialize os dados como uma string JSON. Se o usuário se recusar a responder, retorne success: false com uma mensagem em error.

Continue acompanhando os eventos da sessão depois de retornar a resposta. As funções auxiliares de aprovação do navegador apresentadas anteriormente processam o acesso a origens e o login. Amplie o manipulador de eventos para que ele também processe as chamadas à ferramenta de perguntas.

O modelo pode ver os resultados das ferramentas de função, e esses resultados ficam salvos no histórico da sessão. Colete senhas e códigos de verificação por meio da autenticação no navegador.

Retome o processamento de aprovações

Se o aplicativo perder a conexão ou o envio de uma resposta de aprovação falhar, consulte a mesma sessão e verifique a lista atual de required_actions antes de continuar. Recrie os formulários apenas para as solicitações ainda pendentes e remova os controles das solicitações que já não constam na lista.

Se o fluxo de eventos for interrompido, siga as instruções para recuperar o fluxo e voltar a receber eventos. Ao restabelecer a conexão, o aplicativo não deve reenviar automaticamente a tarefa nem uma resposta de aprovação.

Use o status da resposta para decidir como prosseguir:

Resultado O que o aplicativo deve fazer
202 Limpe os valores enviados e acompanhe os eventos da sessão para verificar o resultado.
400 Confira se o tipo de resposta, a opção selecionada, os IDs dos campos e os valores obrigatórios correspondem à solicitação pendente. Omita os campos nas respostas de cancelamento e de acesso a origens.
404 Verifique o ID da sessão, o ID da solicitação e o tipo de resposta. Consulte a sessão novamente, pois a solicitação pode não estar mais disponível.
409 Consulte a sessão novamente. A solicitação pode ter expirado, o turno correspondente pode ter terminado ou outra resposta pode já ter sido aceita.
Conexão perdida antes da confirmação de recebimento Considere incerto se a resposta foi aceita. Restabeleça a conexão e consulte a sessão antes de decidir se deve tentar novamente.

As solicitações de autenticação expiram após cinco minutos, e o turno ao qual pertencem pode terminar enquanto o usuário preenche os dados. Consulte a sessão novamente antes de restaurar um formulário de login.

Se precisar reenviar uma resposta de autenticação, use o mesmo request_id, a mesma opção selecionada e os mesmos valores nos respectivos campos. Um reenvio idêntico não preenche novamente o formulário do navegador. Se você alterar os valores após a aceitação da resposta, a API retornará 409. Uma nova tentativa de login exige uma nova solicitação do agente.

Para aprovações de acesso a origens, reenvie a mesma decisão se a entrega falhar. Se você alterar uma decisão já aceita, a API retornará 409. As solicitações de acesso a origens permanecem pendentes durante o turno ao qual pertencem e não estão sujeitas ao prazo de cinco minutos das solicitações de autenticação.

Controle o acesso à rede

Use a configuração network do ambiente hospedado para controlar o acesso de saída tanto do navegador quanto do código executado no ambiente. Permita o acesso ao site de destino e aos domínios necessários para carregar recursos da página ou seguir redirecionamentos.

A aprovação de acesso a uma origem é uma decisão separada do usuário e não se sobrepõe à política de rede. Consulte as configurações de acesso à rede para configurar o ambiente.

Continue a sessão e libere os recursos

Reutilize a mesma sessão em tarefas posteriores que precisem do estado do navegador. Os cookies de login podem expirar, e a reciclagem do ambiente limpa o estado do navegador.

Quando terminar, recupere os resultados necessários e exclua a sessão para solicitar a limpeza do ambiente:

Exclua a sessão do navegador
await client.beta.agents.sessions.delete(session.id);

Consulte Sandboxes hospedados pela OpenAI para saber quanto tempo o ambiente permanece ativo e como funciona a exclusão.

Referência para o processamento de solicitações

Limites de envio de dados de autenticação

Cada envio pode incluir até seis valores de campos, sem repetir nenhum campo. Cada valor pode ter até 16.384 caracteres. Os valores serializados dos campos e a opção selecionada, juntos, não podem exceder 120 KiB.

Use os IDs da solicitação e dos campos que constam na aprovação pendente e forneça um valor não vazio para cada campo obrigatório. Consulte a referência da API de eventos da sessão para ver o schema da solicitação.

Exemplo detalhado de processamento de solicitações e do fluxo de eventos com cURL

Use esta versão quando precisar distinguir falhas de transporte, erros HTTP e respostas inválidas à criação da sessão. Ela também filtra a saída do fluxo e informa os tipos e códigos de erro. Assim como no primeiro exemplo, use dois terminais e processe as aprovações no segundo terminal à medida que as solicitações chegarem.

Crie uma sessão e examine as falhas no fluxo de eventos
create_browser_session() {
  unset session_id
  local result http_status body curl_status
  if result=$(curl --silent --fail-with-body --write-out '\n%{http_code}' \
    https://api.openai.com/v1/agents/sessions \
    -H "OpenAI-Beta: agents=v1" \
    -H "Authorization: Bearer $OPENAI_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "agent": {
        "model": "gpt-6-astra",
        "instructions": "Read public documentation in the browser. Do not sign in or change any website data. Report the page title and URL you find.",
        "tools": [{ "type": "computer_use", "include_screenshots": true }]
      },
      "environment": {
        "type": "openai_hosted",
        "desktop": { "enabled": true },
        "network": { "access": "enabled" }
      }
    }'); then curl_status=0; else curl_status=$?; fi
  http_status=$(printf '%s\n' "$result" | tail -n 1)
  body=$(printf '%s\n' "$result" | sed '$d')
  [[ "$http_status" =~ ^[0-9]{3}$ ]] || http_status=000

  if [ "$curl_status" -ne 0 ] || [[ ! "$http_status" =~ ^2[0-9][0-9]$ ]]; then
    printf '%s' "$body" | jq --raw-input --slurp --compact-output \
      --arg status "$http_status" --arg curl_status "$curl_status" '
        def identifier:
          if type == "string" and test("^[A-Za-z][A-Za-z0-9_]{0,79}$") then . else null end;
        (try fromjson catch {}) as $response
        | (if ($response | type) == "object" then $response.error // $response else {} end) as $error
        | if $curl_status != "0" and $curl_status != "22" then
            {status: $status, type: "transport_error", code: ("curl_" + $curl_status)}
          else
            {status: $status, type: ((try ($error.type | identifier) catch null) // "http_error"),
             code: (try ($error.code | identifier) catch null)}
          end' >&2
    return 1
  fi
  if ! session_id=$(printf '%s' "$body" | jq --exit-status --raw-output \
    'select(type == "object") | .id | select(type == "string" and length > 0)' 2>/dev/null); then
    unset session_id
    printf '{"status":"%s","type":"invalid_response","code":"missing_session_id"}\n' "$http_status" >&2
    return 1
  fi
  printf 'Session ID: %s\n' "$session_id"
}
create_browser_session

# Terminal 1: use session_id from the creation request.
# Keep this stream open. Wait for HTTP 200 before sending input.
set -o pipefail
curl --silent --show-error --dump-header - --suppress-connect-headers \
  --no-buffer --fail-with-body \
  "https://api.openai.com/v1/agents/sessions/$session_id/events" \
  -H "OpenAI-Beta: agents=v1" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Accept: text/event-stream" \
  | jq --null-input --raw-input --compact-output --unbuffered '
      def identifier:
        if type == "string" and test("^[A-Za-z][A-Za-z0-9_]{0,79}$") then . else null end;
      def safe_error:
        if type == "object" then {type: (.type | identifier), code: (.code | identifier)} else null end;
      def public_event:
        if .type == "agent.session.turn.output_text.done" then {type, text}
        elif .type == "agent.session.turn.completed" or .type == "agent.session.turn.failed" or .type == "agent.session.turn.cancelled" then
          {type, turn_id: .turn.id, subagent_id: .turn.subagent_id, error: (.turn.error | safe_error)}
        elif .type == "error" or .type == "agent.session.failed" or .type == "agent.session.environment.failed" then
          {type, error: ((.error // .session.error // .environment.error) | safe_error)}
        elif .type == "agent.session.requires_action" then {type}
        else empty end;
      foreach inputs as $raw (
        {body: "", headers: false, failed: false, output: []};
        .output = []
        | ($raw | rtrimstr([13] | implode)) as $line
        | if ($line | startswith("HTTP/")) then
            (try ($line | capture("^(?<protocol>HTTP/[0-9.]+) (?<status>[0-9]{3})(?: |$)")) catch null) as $http
            | if $http == null then . else
                .body = "" | .headers = true | .status = $http.status
                | .failed = (($http.status | tonumber) >= 300)
                | .output = [$http.protocol + " " + $http.status]
              end
          elif .headers then
            if $line == "" then .headers = false else . end
          elif ($line | startswith("data:")) then
            (try ($line | ltrimstr("data:") | fromjson) catch null) as $event
            | .output = [$event | select(type == "object") | public_event]
          elif .failed and .body != null then
            .body += ($line + "\n")
            | (try (.body | fromjson) catch null) as $body
            | if ($body | type) == "object" then
                (($body.error // $body) | safe_error) as $error
                | .output = [{status: .status, type: ($error.type // "http_error"), code: $error.code}]
                | .body = null
              else . end
          else . end;
        .output[])'

# Terminal 2: replace sess_123 with the ID printed in terminal 1.
# Export OPENAI_API_KEY in this terminal too.
session_id="sess_123"
curl --fail-with-body "https://api.openai.com/v1/agents/sessions/$session_id/events" \
  -H "OpenAI-Beta: agents=v1" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [{
      "type": "agent.session.input.message",
      "input": [{
        "role": "user",
        "content": [{
          "type": "input_text",
          "text": "Open https://developers.openai.com in the browser. Find the Agents API quickstart, then report its page title and URL."
        }]
      }]
    }]
  }'