Skip to main content

Gancho de uso de pré-ferramenta

O onPreToolUse gancho é chamado antes da execução de uma ferramenta. Use-o para:

  • Aprovar ou negar a execução da ferramenta
  • Modificar argumentos de ferramenta
  • Adicionar contexto para a ferramenta
  • Suprimir a saída da ferramenta da conversa

Assinatura de Hook

Idiomas de código navigation

TypeScript
import type { PreToolUseHookInput, HookInvocation, PreToolUseHookOutput } from "@github/copilot-sdk";
type PreToolUseHandler = (
  input: PreToolUseHookInput,
  invocation: HookInvocation
) => Promise<PreToolUseHookOutput | null | undefined>;
type PreToolUseHandler = (
  input: PreToolUseHookInput,
  invocation: HookInvocation
) => Promise<PreToolUseHookOutput | null | undefined>;

Entrada

CampoTipoDescription
timestampnúmeroCarimbo de data/hora Unix de quando o gancho foi desencadeado
cwdcadeiaDiretório de trabalho atual
toolNamecadeiaNome da ferramenta que está sendo chamada
toolArgsobjetoArgumentos passados para a ferramenta

Saída

Retornar null ou undefined para permitir que a ferramenta seja executada sem alterações. Caso contrário, retorne um objeto com qualquer um desses campos:

CampoTipoDescription
permissionDecision
"allow"
|
"deny"
|
"ask"
Se deve permitir a chamada de ferramenta
permissionDecisionReasoncadeiaExplicação mostrada ao usuário (para negar/perguntar)
modifiedArgsobjetoArgumentos modificados a serem passados para a ferramenta
additionalContextcadeiaContexto extra injetado na conversa
suppressOutputbooleanSe for verdadeiro, o resultado da ferramenta não aparecerá na conversa

Decisões de permissão

DecisãoBehavior
"allow"A ferramenta é executada normalmente
"deny"A ferramenta está bloqueada, motivo mostrado ao usuário
"ask"O usuário é solicitado a aprovar (modo interativo)

Exemplos

Permitir todas as ferramentas (somente registro em log)

Idiomas de código navigation

TypeScript
const session = await client.createSession({
  hooks: {
    onPreToolUse: async (input, invocation) => {
      console.log(`[${invocation.sessionId}] Calling ${input.toolName}`);
      console.log(`  Args: ${JSON.stringify(input.toolArgs)}`);
      return { permissionDecision: "allow" };
    },
  },
});

Bloquear ferramentas específicas

const BLOCKED_TOOLS = ["shell", "bash", "write_file", "delete_file"];

const session = await client.createSession({
  hooks: {
    onPreToolUse: async (input) => {
      if (BLOCKED_TOOLS.includes(input.toolName)) {
        return {
          permissionDecision: "deny",
          permissionDecisionReason: `Tool '${input.toolName}' is not permitted in this environment`,
        };
      }
      return { permissionDecision: "allow" };
    },
  },
});

Modificar argumentos de ferramenta

const session = await client.createSession({
  hooks: {
    onPreToolUse: async (input) => {
      // Add a default timeout to all shell commands
      if (input.toolName === "shell" && input.toolArgs) {
        const args = input.toolArgs as { command: string; timeout?: number };
        return {
          permissionDecision: "allow",
          modifiedArgs: {
            ...args,
            timeout: args.timeout ?? 30000, // Default 30s timeout
          },
        };
      }
      return { permissionDecision: "allow" };
    },
  },
});

Restringir o acesso a arquivos a diretórios específicos

const ALLOWED_DIRECTORIES = ["/home/user/projects", "/tmp"];

const session = await client.createSession({
  hooks: {
    onPreToolUse: async (input) => {
      if (input.toolName === "read_file" || input.toolName === "write_file") {
        const args = input.toolArgs as { path: string };
        const isAllowed = ALLOWED_DIRECTORIES.some(dir => 
          args.path.startsWith(dir)
        );
        
        if (!isAllowed) {
          return {
            permissionDecision: "deny",
            permissionDecisionReason: `Access to '${args.path}' is not permitted. Allowed directories: ${ALLOWED_DIRECTORIES.join(", ")}`,
          };
        }
      }
      return { permissionDecision: "allow" };
    },
  },
});

Suprimir a saída detalhada da ferramenta

const VERBOSE_TOOLS = ["list_directory", "search_files"];

const session = await client.createSession({
  hooks: {
    onPreToolUse: async (input) => {
      return {
        permissionDecision: "allow",
        suppressOutput: VERBOSE_TOOLS.includes(input.toolName),
      };
    },
  },
});

Adicionar contexto com base na ferramenta

const session = await client.createSession({
  hooks: {
    onPreToolUse: async (input) => {
      if (input.toolName === "query_database") {
        return {
          permissionDecision: "allow",
          additionalContext: "Remember: This database uses PostgreSQL syntax. Always use parameterized queries.",
        };
      }
      return { permissionDecision: "allow" };
    },
  },
});

Práticas recomendadas

  1. Sempre retornar uma decisão – retornar null permite a ferramenta, mas ser explícito com { permissionDecision: "allow" } é mais claro.

  2. Fornecer razões úteis de negação – ao negar, explique por que os usuários entendem:

    return {
      permissionDecision: "deny",
      permissionDecisionReason: "Shell commands require approval. Please describe what you want to accomplish.",
    };
    
  3. Tenha cuidado com a modificação do argumento – verifique se os args modificados mantêm o esquema esperado para a ferramenta.

  4. Considere o desempenho - Os hooks de pré-ferramenta são executados de forma síncrona antes de cada chamada à ferramenta. Mantenha-os rápidos.

  5.           **Use `suppressOutput` de forma criteriosa** – suprimir a saída significa que o modelo não verá o resultado, o que pode afetar a qualidade da conversa.
    

Consulte também