CH 11 · Ferramentas e Sandbox
Objetivo do capítulo
Nos capítulos anteriores, você viu o Agent em ação: ele lê arquivos por conta própria, executa comandos, pesquisa na web e abre um diálogo pedindo confirmação sobre operações sensíveis. Este capítulo desmonta "ferramenta" e "sandbox" — como uma ferramenta é chamada, por quais verificações ela passa; como o sandbox mantém o Agent confinado, e o que acontece quando ele atinge o limite. Quando você entender esses dois mecanismos, saberá por que ele "ousa" agir no seu computador, e o que de fato ele não pode tocar.
Ferramentas: as "mãos" do Agent
No dsh, o Agent em si não consegue mover nada; todas as suas "ações" são feitas por meio de ferramentas — ler arquivos, executar comandos, pesquisar na web, cada uma é uma ferramenta. CH 08 disse que ferramentas são "o armário + o porteiro"; vamos detalhar um pouco mais.
Uma ferramenta no sistema tem este formato:
| Parte | O que faz |
|---|---|
| schema | As "instruções" voltadas para o modelo: nome, descrição, parâmetros (JSON Schema) |
| Função de execução | O código que de fato realiza o trabalho |
| Declaração de saída | A estrutura que deve ser retornada ao terminar |
| Metadados de agendamento | Se pode rodar em paralelo, timeout, como é exibida na UI |
O ponto-chave é o primeiro: na visão do modelo só existem o nome, a descrição e os parâmetros de uma ferramenta — a função de execução, declaração de saída, timeout, flag de paralelo, nenhum deles é visível para o modelo. Esta é a primeira camada de segurança: o modelo sabe "esta ferramenta existe, os parâmetros são preenchidos assim", mas não sabe como ela é implementada internamente, e não pode contornar a lógica de execução.
Uma chamada de ferramenta: um pipeline extensível
Depois que o modelo diz para chamar uma ferramenta, ela não é executada diretamente; em vez disso, passa por um pipeline extensível. A equipe oficial fez esse pipeline de modo que cada etapa possa ser interceptada ou ampliada por plugins — mais um caso de "tudo é um plugin" (um estágio opcional finalizeContent foi omitido do diagrama; é um callback de fim-de-pipeline próprio da ferramenta, não afeta o fluxo principal):
Passo a passo, na ordem:
- Requisição do modelo: o modelo emite um tool/call (nome da ferramenta + parâmetros). Os parâmetros são validados primeiro; se inválidos, um erro é lançado diretamente (
INVALID_ARGS), e nunca chega a ser executada. - pre-execute: o primeiro ponto de checagem. Aqui se decide se uma chamada é allow / deny / ask — o diálogo de aprovação que você vê na UI acontece nesta camada.
- guard: um guarda monotônico, que só pode ficar mais restritivo, não mais frouxo, impedindo que algum estágio afrouxe silenciosamente o limite.
- execute: executa de fato. O sandbox é montado nesta etapa — antes de o comando rodar de verdade, ele é envolto numa casca de arquivo (veja abaixo).
- post-execute: inspeciona o resultado, pode substituí-lo se necessário.
- result: produz o resultado autoritativo, alimenta o modelo, entra na próxima rodada.
Cada etapa pode receber hooks pendurados por plugins — por isso mais tarde, ao escrever plugins, você pode fazer um plugin que "intercepta certas chamadas de ferramenta" (CH 21 cobre hooks). Ao ler esse pipeline, você sabe onde estão montados os "componentes de segurança" — aprovação, sandbox, log.
Sandbox: uma "casca de arquivo" em torno dos comandos
CH 04 cobriu os três níveis de permissão (read-only / workspace-write / danger-full-access), na perspectiva da operação da UI. Aqui vemos o mecanismo: o sandbox governa apenas efeitos no sistema de arquivos; visibilidade de rede e processos não estão na sua jurisdição.
A equipe oficial desenhou o sandbox em duas camadas separadas — "política" e "backend":
- Política (SandboxPolicy): re-analisada a cada chamada — modo + raiz do workspace. A raiz do workspace é derivada do cwd da sessão atual.
- Backend (SandboxProvider): envolve o comando num processo restrito para a plataforma atual. Cada plataforma tem sua implementação — Linux usa bwrap / Landlock (controle de acesso sem privilégios a nível de kernel), macOS usa Seatbelt, Windows usa um runner com token restrito por ACL.
Alguns designs que vale a pena lembrar:
fail-closed: este é o pilar da sua segurança. Se não houver backend de sandbox disponível no ambiente atual, o sistema reporta diretamente um erro SANDBOX_UNAVAILABLE, nunca rebaixa silenciosamente para "rodar nu sem sandbox". Melhor recusar a execução do que correr o risco de soltar.
danger-full-access não envolve uma casca: apenas os modos restritos (read-only / workspace-write) passam pelo wrapper do sandbox. O modo de permissão total faz spawn do comando original sem isolamento de arquivo — e é por isso que a UI confirma duas vezes quando você alterna para o terceiro nível.
Integridade obrigatória dividida em full / partial: na maior parte do tempo o backend consegue governar todos os efeitos de arquivo prometidos (full); mas em ABIs de kernel Linux mais antigos ou em alguns limites do Windows, ele só consegue governar parte deles (partial), e qualquer cenário que exija garantias absolutas precisa saber disso. Para uso diário comum, o padrão workspace-write é estável o suficiente.
Mãos à obra: veja por si mesmo
Passo 1: veja uma chamada de ferramenta na Trajectory
Na Web UI, execute uma tarefa que faça alguma ação (por exemplo, o tipo de resumo de repositório do CH 05). Quando terminar, mude para a aba Trajectory e clique em qualquer linha TOOL. O painel lateral tem quatro abas-chave, que correspondem exatamente à estrutura de ferramenta acima:
- Schema: as "instruções" da ferramenta (nome, descrição, parâmetros)
- Payload: os parâmetros reais enviados desta vez
- Result: o resultado retornado
- Summary / Timing: resumo e tempo decorrido
A imagem abaixo é uma chamada real: à esquerda, uma linha TOOL (web_search) selecionada na linha do tempo; à direita, todas as abas expandidas no painel; na parte inferior, dá para ver as estatísticas gerais da rodada — note que no meio também há dois comandos pwsh que falharam por problemas de rede, e o Agent imediatamente migrou para web_search. Este é exatamente um exemplo real de "ferramentas podem mudar de caminho quando falham":

Passo 2: veja uma aprovação
Sob a permissão padrão workspace-write, peça ao Agent para escrever um arquivo fora do workspace. Aqui, eu deixei ele criar um arquivo de saudação em E:\software-workspace\doubaowork\doubao — esse diretório não está no workspace atual:

Observe que o que realmente acontece ocorre em duas etapas:
- A primeira escrita bate na parede diretamente — a Trajectory mostra
Write · Error: [sandbox: file access denied under workspace-write mode]. - O Agent percebe que o destino está fora do workspace e solicita proativamente a escalação; o diálogo ask na camada pre-execute só aparece nesse momento: elevar o sandbox para danger-full-access, com uma razão. Os dois botões na parte inferior — Deny e Allow once:

Clique em "Allow once", ele só permite esta escrita específica; clique em "Deny", e ele precisa encontrar outro caminho.
Passo 3: alterne para read-only e veja
Na caixa de entrada digite /permission, alterne para read-only (após a entrada, a UI mostrará permission · preset read-only), e peça ao Agent para escrever um arquivo. O resultado é semelhante ao anterior, mas com uma diferença-chave:

- A primeira escrita também bate na parede — mas a mensagem de erro é diferente:
Write · Error: [sandbox: file access denied under read-only mode]. - O Agent também pede escalação — mas desta vez o alvo é
escalate sandbox to workspace-write, não danger-full-access (precisa apenas de permissão de escrita comum, sem precisar elevar até o topo).
Comparando os três casos "bloqueados", fica claro: independentemente do nível de permissão, quando uma escrita falha, o Agent bate na parede primeiro, depois abre o diálogo pedindo confirmação. As diferenças estão na mensagem de erro (workspace-write mode / read-only mode) e no próximo nível solicitado (danger-full-access / workspace-write). O botão "Deny" está sempre lá — este é o núcleo do design do sandbox: o Agent pode "pedir", mas "dar ou não" é sempre com você.
O que você aprendeu neste capítulo
Você passa se conseguir completar os itens abaixo:
- [ ] Dizer de quais partes uma ferramenta é composta, e quais são visíveis para o modelo, quais não são
- [ ] Desenhar o pipeline de execução de ferramenta (model request → pre-execute → guard → execute → post-execute → result), e dizer onde aprovação e sandbox estão montados
- [ ] Explicar o que significa o sandbox "governar apenas efeitos no sistema de arquivos", e por quê
- [ ] Explicar fail-closed: o que o sistema faz quando não há backend de sandbox disponível (reporta SANDBOX_UNAVAILABLE, não roda nu)
- [ ] Clicar para abrir uma chamada de ferramenta na Trajectory e entender Schema / Payload / Result
- [ ] Dizer os erros quando escritas são negadas em diferentes níveis de permissão (workspace-write mode / read-only mode) e os alvos de escalação que o Agent pede (danger-full-access / workspace-write)
- [ ] Saber explicar: quando uma escrita falha, o Agent bate na parede primeiro e depois abre um diálogo, mas o "Deny" está sempre nas suas mãos
