Skip to main content

Хук, присланный пользовательским запросом

onUserPromptSubmitted Крюк вызывается, когда пользователь отправляет сообщение. Он используется для следующих задач:

  • Изменять или улучшать пользовательские подсказки
  • Добавьте контекст перед обработкой
  • Фильтруйте или проверяйте ввод пользователя
  • Реализация шаблонов запросов

Сигнатура крюка

Языки кода navigation

TypeScript
import type { UserPromptSubmittedHookInput, HookInvocation, UserPromptSubmittedHookOutput } from "@github/copilot-sdk";
type UserPromptSubmittedHandler = (
  input: UserPromptSubmittedHookInput,
  invocation: HookInvocation
) => Promise<UserPromptSubmittedHookOutput | null | undefined>;
type UserPromptSubmittedHandler = (
  input: UserPromptSubmittedHookInput,
  invocation: HookInvocation
) => Promise<UserPromptSubmittedHookOutput | null | undefined>;

Input

ПолеТипDescription
timestampnumberВременная метка Unix, когда срабатывал крюк
cwdstringТекущий рабочий справочник
promptstringЗапрос пользователя, отправленный

Выходные данные

Вернуть null или undefined использовать запрос без изменений. В противном случае верните объект с любым из следующих полей:

ПолеТипDescription
modifiedPromptstringИзменённая подсказка для использования вместо оригинального
additionalContextstringДополнительный контекст в разговор
suppressOutputbooleanЕсли это верно, подавить ответный сигнал ассистента

Примеры

Логировать все пользовательские запросы

Языки кода navigation

TypeScript
const session = await client.createSession({
  hooks: {
    onUserPromptSubmitted: async (input, invocation) => {
      console.log(`[${invocation.sessionId}] User: ${input.prompt}`);
      return null; // Pass through unchanged
    },
  },
});

Добавить контекст проекта

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)) {
          // Replace the prompt with a warning message
          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 NOTICE_THRESHOLD = 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();
      }

      promptTimestamps.push(now);
      if (promptTimestamps.length >= NOTICE_THRESHOLD) {
        // This is advisory context for the model, not an enforced rate limit.
        // Enforce hard limits before calling session.send().
        return {
          additionalContext: `The user has sent ${promptTimestamps.length} prompts in the last minute. Suggest waiting before sending more.`,
        };
      }

      return null;
    },
  },
});

Шаблоны запросов

const TEMPLATES: Record<string, (args: string) => string> = {
  "bug:": (desc) => `I found a bug: ${desc}

Please help me:
1. Understand why this is happening
2. Suggest a fix
3. Explain how to prevent similar bugs`,

  "feature:": (desc) => `I want to implement this feature: ${desc}

Please:
1. Outline the implementation approach
2. Identify potential challenges
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;
    },
  },
});

Лучшие практики

  1. Сохраняйте пользовательское намерение — при изменении запросов убедитесь, что основное намерение остаётся ясным.

  2. Будьте прозрачны в отношении изменений — если вы значительно изменили запрос, подумайте о логировании или уведомлении пользователя.

  3. Use additionalContext over modifiedPrompt — добавление контекста менее навязчиво, чем переписывание запроса.

  4. Использование additionalContext рекомендаций. Этот перехватчик не может отклонить запрос или применить политику. Принудительное применение жестких ограничений перед вызовом session.send().

  5. Держите обработку быстро — этот крючок работает на каждом пользовательском сообщении. Избегайте медленных операций.

См. также