Thanks to visit codestin.com
Credit goes to docs.github.com

Skip to main content

Haken zur Verwendung vor Werkzeugen

Der onPreToolUse Hook wird aufgerufen , bevor ein Tool ausgeführt wird. Verwenden Sie es zu folgenden Zwecken:

  • Genehmigen oder Verweigern der Toolausführung
  • Ändern von Toolargumenten
  • Hinzufügen von Kontext für das Tool
  • Toolausgabe aus der Unterhaltung unterdrücken

Hook-Signatur

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>;
Python
from copilot.session import PreToolUseHookInput, PreToolUseHookOutput
from typing import Callable, Awaitable

PreToolUseHandler = Callable[
    [PreToolUseHookInput, dict[str, str]],
    Awaitable[PreToolUseHookOutput | None]
]
PreToolUseHandler = Callable[
    [PreToolUseHookInput, dict[str, str]],
    Awaitable[PreToolUseHookOutput | None]
]
Go
package main

import copilot "github.com/github/copilot-sdk/go"

type PreToolUseHandler func(
    input copilot.PreToolUseHookInput,
    invocation copilot.HookInvocation,
) (*copilot.PreToolUseHookOutput, error)

func main() {}
type PreToolUseHandler func(
    input PreToolUseHookInput,
    invocation HookInvocation,
) (*PreToolUseHookOutput, error)
.NET
using GitHub.Copilot;

public delegate Task<PreToolUseHookOutput?> PreToolUseHandler(
    PreToolUseHookInput input,
    HookInvocation invocation);
public delegate Task<PreToolUseHookOutput?> PreToolUseHandler(
    PreToolUseHookInput input,
    HookInvocation invocation);
Java
import com.github.copilot.sdk.json.*;

PreToolUseHandler preToolUseHandler;

Eingabe

FeldTypDescription
timestampZahlUnix-Zeitstempel, zu dem der Hook ausgelöst wurde
cwdstringAktuelles Arbeitsverzeichnis
toolNamestringName des aufgerufenen Tools
toolArgsObjektAn das Tool übergebene Argumente

Output

Geben Sie null oder undefined zurück, um das Tool ohne Änderungen auszuführen. Geben Sie andernfalls ein Objekt mit einem der folgenden Felder zurück:

FeldTypDescription
permissionDecision
"allow"
|
"deny"
|
"ask"
Gibt an, ob der Toolaufruf zugelassen werden soll.
permissionDecisionReasonstringErläuterung, die dem Benutzer angezeigt wird (zur Ablehnung/Frage)
modifiedArgsObjektGeänderte Argumente, die an das Tool übergeben werden sollen
additionalContextstringZusätzlicher Kontext, der in die Unterhaltung eingefügt wurde
suppressOutputbooleanWenn wahr, wird die Toolausgabe nicht in Unterhaltungen angezeigt.

Berechtigungsentscheidungen

EntscheidungBehavior
"allow"Das Tool wird normal ausgeführt
"deny"Tool ist blockiert, Grund, der dem Benutzer angezeigt wird
"ask"Der Benutzer wird aufgefordert, den Zugriff (im interaktiven Modus) zu genehmigen.

Examples

Alle Tools zulassen (nur Protokollierung)

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" };
    },
  },
});
Python
from copilot.session import PermissionHandler

async def on_pre_tool_use(input_data, invocation):
    print(f"[{invocation['session_id']}] Calling {input_data['toolName']}")
    print(f"  Args: {input_data['toolArgs']}")
    return {"permissionDecision": "allow"}

session = await client.create_session(on_permission_request=PermissionHandler.approve_all, hooks={"on_pre_tool_use": on_pre_tool_use})
Go
package main

import (
    "context"
    "fmt"
    copilot "github.com/github/copilot-sdk/go"
)

func main() {
    client := copilot.NewClient(nil)
    session, _ := client.CreateSession(context.Background(), &copilot.SessionConfig{
        OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
        Hooks: &copilot.SessionHooks{
            OnPreToolUse: func(input copilot.PreToolUseHookInput, inv copilot.HookInvocation) (*copilot.PreToolUseHookOutput, error) {
                fmt.Printf("[%s] Calling %s\n", inv.SessionID, input.ToolName)
                fmt.Printf("  Args: %v\n", input.ToolArgs)
                return &copilot.PreToolUseHookOutput{
                    PermissionDecision: "allow",
                }, nil
            },
        },
    })
    _ = session
}
session, _ := client.CreateSession(context.Background(), &copilot.SessionConfig{
    Hooks: &copilot.SessionHooks{
        OnPreToolUse: func(input copilot.PreToolUseHookInput, inv copilot.HookInvocation) (*copilot.PreToolUseHookOutput, error) {
            fmt.Printf("[%s] Calling %s\n", inv.SessionID, input.ToolName)
            fmt.Printf("  Args: %v\n", input.ToolArgs)
            return &copilot.PreToolUseHookOutput{
                PermissionDecision: "allow",
            }, nil
        },
    },
})
.NET
using GitHub.Copilot;

public static class PreToolUseExample
{
    public static async Task Main()
    {
        await using var client = new CopilotClient();
        var session = await client.CreateSessionAsync(new SessionConfig
        {
            Hooks = new SessionHooks
            {
                OnPreToolUse = (input, invocation) =>
                {
                    Console.WriteLine($"[{invocation.SessionId}] Calling {input.ToolName}");
                    Console.WriteLine($"  Args: {input.ToolArgs}");
                    return Task.FromResult<PreToolUseHookOutput?>(
                        new PreToolUseHookOutput { PermissionDecision = "allow" }
                    );
                },
            },
        });
    }
}
var session = await client.CreateSessionAsync(new SessionConfig
{
    Hooks = new SessionHooks
    {
        OnPreToolUse = (input, invocation) =>
        {
            Console.WriteLine($"[{invocation.SessionId}] Calling {input.ToolName}");
            Console.WriteLine($"  Args: {input.ToolArgs}");
            return Task.FromResult<PreToolUseHookOutput?>(
                new PreToolUseHookOutput { PermissionDecision = "allow" }
            );
        },
    },
});
Java
import com.github.copilot.sdk.*;
import com.github.copilot.sdk.json.*;
import java.util.concurrent.CompletableFuture;

var hooks = new SessionHooks()
    .setOnPreToolUse((input, invocation) -> {
        System.out.println("[" + invocation.getSessionId() + "] Calling " + input.getToolName());
        System.out.println("  Args: " + input.getToolArgs());
        return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
    });

var session = client.createSession(
    new SessionConfig()
        .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
        .setHooks(hooks)
).get();

Blockieren bestimmter Tools

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

Ändern von Toolargumenten

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

Einschränken des Dateizugriffs auf bestimmte Verzeichnisse

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

Ausführliche Toolausgabe unterdrücken

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

Hinzufügen von Kontext basierend auf dem Tool

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

Bewährte Methoden

  1. Geben Sie immer eine Entscheidung zurück – Die Rückgabe von null erlaubt das Tool, aber die explizite Verwendung von { permissionDecision: "allow" } ist klarer.

  2. Geben Sie hilfreiche Ablehnungsgründe an – Erläutern Sie bei einer Ablehnung, warum, damit Nutzer dies verstehen:

    return {
      permissionDecision: "deny",
      permissionDecisionReason: "Shell commands require approval. Please describe what you want to accomplish.",
    };
    
  3. Achten Sie bei der Argumentänderung darauf , dass geänderte Argen das erwartete Schema für das Tool beibehalten.

  4. Performance berücksichtigen – Pre-Tool-Hooks werden vor jedem Tool-Aufruf synchron ausgeführt. Halten Sie sie schnell bereit.

  5. Verwenden Sie suppressOutput mit Bedacht – Das Unterdrücken der Ausgabe bedeutet, dass das Modell das Ergebnis nicht sieht, was sich auf die Gesprächsqualität auswirken kann.

Siehe auch