- 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
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>;
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]
]
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)
using GitHub.Copilot;
public delegate Task<PreToolUseHookOutput?> PreToolUseHandler(
PreToolUseHookInput input,
HookInvocation invocation);
public delegate Task<PreToolUseHookOutput?> PreToolUseHandler(
PreToolUseHookInput input,
HookInvocation invocation);
import com.github.copilot.sdk.json.*;
PreToolUseHandler preToolUseHandler;
Eingabe
| Feld | Typ | Description |
|---|---|---|
timestamp | Zahl | Unix-Zeitstempel, zu dem der Hook ausgelöst wurde |
cwd | string | Aktuelles Arbeitsverzeichnis |
toolName | string | Name des aufgerufenen Tools |
toolArgs | Objekt | An 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:
| Feld | Typ | Description |
|---|---|---|
permissionDecision | ||
"allow" | ||
| | | ||
"deny" | ||
| | | ||
"ask" | ||
| Gibt an, ob der Toolaufruf zugelassen werden soll. | ||
permissionDecisionReason | string | Erläuterung, die dem Benutzer angezeigt wird (zur Ablehnung/Frage) |
modifiedArgs | Objekt | Geänderte Argumente, die an das Tool übergeben werden sollen |
additionalContext | string | Zusätzlicher Kontext, der in die Unterhaltung eingefügt wurde |
suppressOutput | boolean | Wenn wahr, wird die Toolausgabe nicht in Unterhaltungen angezeigt. |
Berechtigungsentscheidungen
| Entscheidung | Behavior |
|---|---|
"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)
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" };
},
},
});
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})
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
},
},
})
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" }
);
},
},
});
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
-
Geben Sie immer eine Entscheidung zurück – Die Rückgabe von
nullerlaubt das Tool, aber die explizite Verwendung von{ permissionDecision: "allow" }ist klarer. -
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.", }; -
Achten Sie bei der Argumentänderung darauf , dass geänderte Argen das erwartete Schema für das Tool beibehalten.
-
Performance berücksichtigen – Pre-Tool-Hooks werden vor jedem Tool-Aufruf synchron ausgeführt. Halten Sie sie schnell bereit.
-
Verwenden Sie
suppressOutputmit Bedacht – Das Unterdrücken der Ausgabe bedeutet, dass das Modell das Ergebnis nicht sieht, was sich auf die Gesprächsqualität auswirken kann.