Skip to main content

Gancho previo al uso de la herramienta

Se llama al enlace onPreToolUse antes de que se ejecute una herramienta. Úselo para:

  • Aprobación o denegación de la ejecución de la herramienta
  • Modificación de argumentos de herramienta
  • Adición de contexto para la herramienta
  • Suprimir la salida de la herramienta de la conversación

Firma de enlace

Lenguajes de código navigation

TypeScript
type PreToolUseHandler = (
  input: PreToolUseHookInput,
  invocation: HookInvocation
) => Promise<PreToolUseHookOutput | null | undefined>;

Entrada

CampoTipoDescription
timestampnúmeroMarca de tiempo de Unix cuando se desencadenó el enlace
cwdstringDirectorio de trabajo actual
toolNamestringNombre de la herramienta invocada
toolArgsobjectArgumentos pasados a la herramienta

Output

Devuelve null o undefined permite que la herramienta se ejecute sin cambios. De lo contrario, devuelve un objeto con cualquiera de estos campos:

CampoTipoDescription
permissionDecision
"allow"
|
"deny"
|
"ask"
Indica si se va a permitir la llamada a la herramienta
permissionDecisionReasonstringExplicación que se muestra al usuario (para denegar o pedir)
modifiedArgsobjectArgumentos modificados para pasar a la herramienta
additionalContextstringContexto adicional insertado en la conversación
suppressOutputbooleanSi es verdadero, la salida de la herramienta no aparecerá en la conversación

Decisiones de permisos

DecisiónComportamiento
"allow"La herramienta se ejecuta normalmente
"deny"La herramienta está bloqueada, motivo que se muestra al usuario
"ask"Se pide al usuario que apruebe (modo interactivo)

Omitir solicitudes de permisos para herramientas personalizadas de confianza

Si define una herramienta personalizada que es segura para ejecutarse sin preguntar, establezca skipPermission: true en la definición de la herramienta. Utilízala para herramientas de confianza propiedad de la aplicación cuyos datos de entrada ya estén restringidos por tu aplicación; utiliza onPreToolUse cuando necesites comprobaciones de directivas o validación de argumentos por llamada.

const getWeather = defineTool("get_weather", {
  description: "Get weather for a location.",
  parameters: {
    type: "object",
    properties: { location: { type: "string" } },
    required: ["location"],
  },
  skipPermission: true,
  handler: async ({ location }) => ({ forecast: `Sunny in ${location}` }),
});

Ejemplos

Permitir todas las herramientas (solo registro)

Lenguajes 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 herramientas 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" };
    },
  },
});

Modificación de argumentos de herramienta

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" };
    },
  },
});

Restricción del acceso a archivos a directorios 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 la salida detallada de la herramienta

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),
      };
    },
  },
});

Añadir contexto según la herramienta

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" };
    },
  },
});

procedimientos recomendados

  1. Devolver siempre una decisión : devolver null permite la herramienta, pero ser explícito con { permissionDecision: "allow" } es más claro.

  2. Proporcionar razones de denegación útiles : al denegar, explique por qué para que los usuarios comprendan:

    return {
      permissionDecision: "deny",
      permissionDecisionReason: "Shell commands require approval. Please describe what you want to accomplish.",
    };
    
  3. Tenga cuidado con la modificación de argumentos : asegúrese de que los argumentos modificados mantienen el esquema esperado para la herramienta.

  4. Tenga en cuenta el rendimiento - Los hooks previos a la herramienta se ejecutan de forma síncrona antes de cada llamada a la herramienta. Manténgalos rápidos.

  5. Usar suppressOutput con criterio : suprimir la salida significa que el modelo no verá el resultado, lo que puede afectar a la calidad de la conversación.

Consulte también