Примечание.
Второй пилот SDK в настоящее время находится в Technical Preview. Функциональность и доступность могут меняться.
`onUserPromptSubmitted` Крюк вызывается, когда пользователь отправляет сообщение. Он используется для следующих задач:
- Изменять или улучшать пользовательские подсказки
- Добавьте контекст перед обработкой
- Фильтруйте или проверяйте ввод пользователя
- Реализация шаблонов запросов
Сигнатура крюка
import type { UserPromptSubmittedHookInput, HookInvocation, UserPromptSubmittedHookOutput } from "@github/copilot-sdk";
type UserPromptSubmittedHandler = (
input: UserPromptSubmittedHookInput,
invocation: HookInvocation
) => Promise<
UserPromptSubmittedHookOutput | null | undefined
>;
Для сигнатур хуков в Python, Go и .NET см. репозиторийgithub/copilot-sdk.
Ввод
| Поле | Тип | Описание |
|---|---|---|
timestamp | число/номер | Временная метка Unix, когда срабатывал крюк |
cwd | струна | Текущий рабочий справочник |
prompt | струна | Запрос пользователя, отправленный |
Выходные данные
Вернуть null или undefined использовать запрос без изменений. В противном случае верните объект с любым из следующих полей.
| Поле | Тип | Описание |
|---|---|---|
modifiedPrompt | струна | Изменённая подсказка для использования вместо оригинального |
additionalContext | струна | Дополнительный контекст в разговор |
suppressOutput | булевый | Если это верно, подавить ответный сигнал ассистента |
Примеры
Логировать все пользовательские запросы
const session = await client.createSession({
hooks: {
onUserPromptSubmitted: async (
input, invocation
) => {
console.log(
`[${invocation.sessionId}] `
+ `User: ${input.prompt}`
);
return null; // Pass through unchanged
},
},
});
Примеры в Python, Go и .NET см. репозиторийgithub/copilot-sdk.
Добавить контекст проекта
const session = await client.createSession({
hooks: {
onUserPromptSubmitted: async (input) => {
const projectInfo = await getProjectInfo();
return {
additionalContext: `
Project: ${projectInfo.name}
Language: ${projectInfo.language}
Framework: ${projectInfo.framework}
`.trim(),
};
},
},
});
Расширение команд сокращения
const SHORTCUTS: Record<string, string> = {
"/fix":
"Please fix the errors in the code",
"/explain":
"Please explain this code in detail",
"/test":
"Please write unit tests for this code",
"/refactor":
"Please refactor this code to improve "
+ "readability and maintainability",
};
const session = await client.createSession({
hooks: {
onUserPromptSubmitted: async (input) => {
for (const [shortcut, expansion]
of Object.entries(SHORTCUTS)) {
if (input.prompt.startsWith(shortcut)) {
const rest = input.prompt
.slice(shortcut.length).trim();
return {
modifiedPrompt:
`${expansion}`
+ `${rest ? `: ${rest}` : ""}`,
};
}
}
return null;
},
},
});
Фильтрование содержимого
const BLOCKED_PATTERNS = [
/password\s*[:=]/i,
/api[_-]?key\s*[:=]/i,
/secret\s*[:=]/i,
];
const session = await client.createSession({
hooks: {
onUserPromptSubmitted: async (input) => {
for (const pattern of BLOCKED_PATTERNS) {
if (pattern.test(input.prompt)) {
return {
modifiedPrompt:
"[Content blocked: Please don't "
+ "include sensitive credentials "
+ "in your prompts. Use environment "
+ "variables instead.]",
suppressOutput: true,
};
}
}
return null;
},
},
});
Обеспечение длин лимита запросов
const MAX_PROMPT_LENGTH = 10000;
const session = await client.createSession({
hooks: {
onUserPromptSubmitted: async (input) => {
if (input.prompt.length > MAX_PROMPT_LENGTH) {
// Truncate the prompt and add context
return {
modifiedPrompt: input.prompt.substring(0, MAX_PROMPT_LENGTH),
additionalContext: `Note: The original prompt was ${input.prompt.length} characters and was truncated to ${MAX_PROMPT_LENGTH} characters.`,
};
}
return null;
},
},
});
Добавить пользовательские предпочтения
interface UserPreferences {
codeStyle: "concise" | "verbose";
preferredLanguage: string;
experienceLevel: "beginner" | "intermediate" | "expert";
}
const session = await client.createSession({
hooks: {
onUserPromptSubmitted: async (input) => {
const prefs: UserPreferences = await loadUserPreferences();
const contextParts = [];
if (prefs.codeStyle === "concise") {
contextParts.push("User prefers concise code with minimal comments.");
} else {
contextParts.push("User prefers verbose code with detailed comments.");
}
if (prefs.experienceLevel === "beginner") {
contextParts.push("Explain concepts in simple terms.");
}
return {
additionalContext: contextParts.join(" "),
};
},
},
});
Ограничение скорости
const promptTimestamps: number[] = [];
const RATE_LIMIT = 10; // prompts
const RATE_WINDOW = 60000; // 1 minute
const session = await client.createSession({
hooks: {
onUserPromptSubmitted: async (input) => {
const now = Date.now();
// Remove timestamps outside the window
while (promptTimestamps.length > 0 && promptTimestamps[0] < now - RATE_WINDOW) {
promptTimestamps.shift();
}
if (promptTimestamps.length >= RATE_LIMIT) {
return {
reject: true,
rejectReason: `Rate limit exceeded. Please wait before sending more prompts.`,
};
}
promptTimestamps.push(now);
return null;
},
},
});
Шаблоны запросов
const TEMPLATES: Record<
string, (args: string) => string
> = {
"bug:": (desc) =>
`I found a bug: ${desc}\n\n`
+ `Please help me:\n`
+ `1. Understand why this is happening\n`
+ `2. Suggest a fix\n`
+ `3. Explain how to prevent similar bugs`,
"feature:": (desc) =>
`I want to implement this feature: `
+ `${desc}\n\n`
+ `Please:\n`
+ `1. Outline the implementation approach\n`
+ `2. Identify potential challenges\n`
+ `3. Provide sample code`,
};
const session = await client.createSession({
hooks: {
onUserPromptSubmitted: async (input) => {
for (const [prefix, template]
of Object.entries(TEMPLATES)) {
if (
input.prompt.toLowerCase()
.startsWith(prefix)
) {
const args = input.prompt
.slice(prefix.length).trim();
return {
modifiedPrompt: template(args),
};
}
}
return null;
},
},
});
Лучшие практики
-
**Сохраняйте намерение пользователя.** При изменении заданий убедитесь, что основное намерение остаётся ясным. -
**Будьте прозрачны в отношении изменений.** Если вы значительно изменили запрос, подумайте о логировании или уведомлении пользователя. -
**Использовать `additionalContext` над `modifiedPrompt`.** Добавление контекста менее навязчиво, чем переписывание запроса. -
**Указывайте чёткие причины отказа.** Когда вы отклоняете запросы, объясните, почему и как решить проблему. -
**Продолжайте быстро обрабатывать.** Этот крючок работает на каждом пользовательском сообщении. Избегайте медленных операций.
Дополнительные материалы
-
[AUTOTITLE](/copilot/how-tos/copilot-sdk/use-hooks/quickstart) -
[AUTOTITLE](/copilot/how-tos/copilot-sdk/use-hooks/session-lifecycle) -
[AUTOTITLE](/copilot/how-tos/copilot-sdk/use-hooks/pre-tool-use)