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>;

입력

FieldType설명
timestampnumber후크가 트리거될 때의 Unix 타임스탬프
cwdstring현재 작업 디렉터리
promptstring사용자가 제출한 프롬프트

출력

null 또는 undefined를 반환하여 프롬프트를 변경하지 않고 사용합니다. 그렇지 않으면 다음 필드가 있는 개체를 반환합니다.

FieldType설명
modifiedPromptstring원래 대신 사용할 수정된 프롬프트
additionalContextstring대화에 추가된 추가 컨텍스트
suppressOutputbooleantrue이면 도우미의 응답 출력을 표시하지 않습니다.

예제

모든 사용자 프롬프트 기록

코드 언어 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 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}

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. ** additionalContext보다 modifiedPrompt을(를) 사용** - 맥락을 추가하는 것이 프롬프트를 다시 작성하는 것보다 부담이 적습니다.

  4. 명확한 거부 이유 제공 - 프롬프트를 거부할 때 이유와 해결 방법을 설명합니다.

  5. 빠른 처리 유지 - 이 후크는 모든 사용자 메시지에서 실행됩니다. 느린 작업을 방지합니다.

참고하십시오