Примечание.
Второй пилот SDK в настоящее время находится в Technical Preview. Функциональность и доступность могут меняться.
`onPreToolUse` Крюк **вызывается до** запуска инструмента. Он используется для следующих задач:
- Одобрение или отказ в выполнении инструмента
- Изменение аргументов инструментов
- Добавьте контекст для инструмента
- Подавление инструмента из разговора
Сигнатура крюка
import type { PreToolUseHookInput, HookInvocation, PreToolUseHookOutput } from "@github/copilot-sdk";
type PreToolUseHandler = (
input: PreToolUseHookInput,
invocation: HookInvocation
) => Promise<PreToolUseHookOutput | null | undefined>;
Для сигнатур хуков в Python, Go и .NET см. репозиторийgithub/copilot-sdk.
Ввод
| Поле | Тип | Описание |
|---|---|---|
timestamp | число/номер | Временная метка Unix, когда срабатывал крюк |
cwd | струна | Текущий рабочий справочник |
toolName | струна | Название используемого инструмента |
toolArgs | объект | Аргументы, переданные средству |
Выходные данные
Вернуть null или undefined позволить инструменту выполняться без изменений. В противном случае верните объект с любым из следующих полей.
| Поле | Тип | Описание |
|---|---|---|
permissionDecision |
`"allow"`
\|
`"deny"`
\|
`"ask"`
| Разрешать ли вызов инструмента |
| permissionDecisionReason | струна | Объяснение показано пользователю (для отказа/спроса) |
| modifiedArgs | объект | Модифицированные аргументы для передачи инструменту |
| additionalContext | струна | Дополнительный контекст в разговор |
| suppressOutput | булевый | Если это правда, то результат инструмента не будет отображаться в разговоре |
Решения по разрешению
| Решение | Поведение |
|---|---|
"allow" | Инструмент работает нормально |
"deny" | Инструмент заблокирован, причина показана пользователю |
"ask" | Пользователю предлагается одобрить (интерактивный режим) |
Примеры
Разрешить все инструменты (только логирование)
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, Go и .NET см. репозиторийgithub/copilot-sdk.
Инструменты, специфичные для блоков
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" };
},
},
});
Изменение аргументов инструментов
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,
},
};
}
return { permissionDecision: "allow" };
},
},
});
Ограничить доступ к файлам определёнными каталогами
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" };
},
},
});
Подавление многословного вывода инструмента
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),
};
},
},
});
Добавьте контекст на основе инструмента
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" };
},
},
});
Лучшие практики
-
**Всегда возвращайте решение.** Возврат `null` позволяет использовать инструмент, но быть откровенным `{ permissionDecision: "allow" }` становится яснее. -
**Приведите полезные причины для отказа.** При отказе объясните почему, чтобы пользователи поняли, что произошло. -
**Будьте осторожны с модификацией аргументов.** Убедитесь, что модифицированные аргументы сохраняют ожидаемую схему инструмента. -
**Подумайте о результатах.** Предварительные крючки запускаются синхронно перед каждым вызовом инструмента. Держите их быстрыми. -
**Используйте `suppressOutput` с осторожностью.** Подавление выхода означает, что модель не увидит результат, что может повлиять на качество разговора. -
**Будьте осторожны с конфиденциальными данными.** Аргументы и результаты инструментов могут содержать секреты, пути к файлам или личную информацию. Избегайте логирования и раскрытия этих данных в производственных средах.
Дополнительные материалы
-
[AUTOTITLE](/copilot/how-tos/copilot-sdk/use-hooks/quickstart) -
[AUTOTITLE](/copilot/how-tos/copilot-sdk/use-hooks/post-tool-use) -
[AUTOTITLE](/copilot/how-tos/copilot-sdk/use-hooks/error-handling)