Skip to main content

사후 도구 사용 후크

          `onPostToolUse` 후크를 사용하여 도구 결과를 변환하고, 도구 실행을 기록하고, 도구가 실행코필로트 SDK된 후 컨텍스트를 추가합니다.

누가 이 기능을 사용할 수 있나요?

GitHub Copilot SDK 는 모든 Copilot 계획에서 사용할 수 있습니다.

참고

코필로트 SDK가 현재 기술 미리 보기에 있습니다. 기능 및 가용성은 변경될 수 있습니다.

          `onPostToolUse` 도구가 실행된 **후** 후크가 호출됩니다. 이를 사용하여 다음을 수행합니다.
  • 도구 결과 변환 또는 필터링
  • 감사를 위한 로그 도구 실행
  • 결과에 따라 컨텍스트 추가
  • 대화의 결과 표시 안 함

후크 서명

import type { PostToolUseHookInput, HookInvocation, PostToolUseHookOutput } from "@github/copilot-sdk";
type PostToolUseHandler = (
  input: PostToolUseHookInput,
  invocation: HookInvocation
) => Promise<PostToolUseHookOutput | null | undefined>;

Python, Go 및 .NET의 후크 서명은 리포지토리를github/copilot-sdk 참조하세요.

입력

분야유형설명
timestamp숫자후크가 트리거될 때의 Unix 타임스탬프
cwd문자열현재 작업 디렉터리
toolName문자열호출된 도구의 이름
toolArgs객체도구에 전달된 인수
toolResult객체도구에서 반환된 결과

출력

결과를 변경하지 않고 null 또는 undefined을 반환하거나 그대로 전달합니다. 그렇지 않으면 다음 필드 중 하나가 있는 객체를 반환합니다.

분야유형설명
modifiedResult객체원래 대신 사용할 수정된 결과
additionalContext문자열대화에 삽입된 추가 컨텍스트
suppressOutput부울true이면 결과가 대화에 표시되지 않습니다.

예제

모든 도구 결과 기록

const session = await client.createSession({
  hooks: {
    onPostToolUse: async (input, invocation) => {
      console.log(
        `[${invocation.sessionId}] `
        + `Tool: ${input.toolName}`
      );
      console.log(
        `  Args: ${JSON.stringify(input.toolArgs)}`
      );
      console.log(
        `  Result: `
        + `${JSON.stringify(input.toolResult)}`
      );
      return null; // Pass through unchanged
    },
  },
});

Python, Go 및 .NET의 예제는 리포지토리를github/copilot-sdk 참조하세요.

중요한 데이터 수정

const SENSITIVE_PATTERNS = [
  /api[_-]?key["\s:=]+["']?[\w-]+["']?/gi,
  /password["\s:=]+["']?[\w-]+["']?/gi,
  /secret["\s:=]+["']?[\w-]+["']?/gi,
];

const session = await client.createSession({
  hooks: {
    onPostToolUse: async (input) => {
      if (typeof input.toolResult === "string") {
        let redacted = input.toolResult;
        for (const pattern of SENSITIVE_PATTERNS) {
          redacted = redacted.replace(
            pattern, "[REDACTED]"
          );
        }

        if (redacted !== input.toolResult) {
          return { modifiedResult: redacted };
        }
      }
      return null;
    },
  },
});

대용량 결과 잘라내기

const MAX_RESULT_LENGTH = 10000;

const session = await client.createSession({
  hooks: {
    onPostToolUse: async (input) => {
      const resultStr =
        JSON.stringify(input.toolResult);

      if (resultStr.length > MAX_RESULT_LENGTH) {
        return {
          modifiedResult: {
            truncated: true,
            originalLength: resultStr.length,
            content:
              resultStr.substring(
                0, MAX_RESULT_LENGTH
              ) + "...",
          },
          additionalContext:
            `Note: Result was truncated from `
            + `${resultStr.length} to `
            + `${MAX_RESULT_LENGTH} characters.`,
        };
      }
      return null;
    },
  },
});

결과에 따라 컨텍스트 추가

const session = await client.createSession({
  hooks: {
    onPostToolUse: async (input) => {
      // If a file read returned an error,
      // add helpful context
      if (
        input.toolName === "read_file"
        && input.toolResult?.error
      ) {
        return {
          additionalContext:
            "Tip: If the file doesn't exist, "
            + "consider creating it or "
            + "checking the path.",
        };
      }

      // If shell command failed,
      // add debugging hint
      if (
        input.toolName === "shell"
        && input.toolResult?.exitCode !== 0
      ) {
        return {
          additionalContext:
            "The command failed. Check if "
            + "required dependencies are installed.",
        };
      }

      return null;
    },
  },
});

필터 오류 스택 추적

const session = await client.createSession({
  hooks: {
    onPostToolUse: async (input) => {
      if (input.toolResult?.error && input.toolResult?.stack) {
        // Remove internal stack trace details
        return {
          modifiedResult: {
            error: input.toolResult.error,
            // Keep only first 3 lines of stack
            stack: input.toolResult.stack.split("\n").slice(0, 3).join("\n"),
          },
        };
      }
      return null;
    },
  },
});

규정 준수에 대한 감사 내역

interface AuditEntry {
  timestamp: number;
  sessionId: string;
  toolName: string;
  args: unknown;
  result: unknown;
  success: boolean;
}

const auditLog: AuditEntry[] = [];

const session = await client.createSession({
  hooks: {
    onPostToolUse: async (input, invocation) => {
      auditLog.push({
        timestamp: input.timestamp,
        sessionId: invocation.sessionId,
        toolName: input.toolName,
        args: input.toolArgs,
        result: input.toolResult,
        success: !input.toolResult?.error,
      });

      // Optionally persist to database/file
      await saveAuditLog(auditLog);

      return null;
    },
  },
});

시끄러운 결과 표시 안 함

const NOISY_TOOLS = ["list_directory", "search_codebase"];

const session = await client.createSession({
  hooks: {
    onPostToolUse: async (input) => {
      if (NOISY_TOOLS.includes(input.toolName)) {
        // Summarize instead of showing full result
        const items = Array.isArray(input.toolResult) 
          ? input.toolResult 
          : input.toolResult?.items || [];
        
        return {
          modifiedResult: {
            summary: `Found ${items.length} items`,
            firstFew: items.slice(0, 5),
          },
        };
      }
      return null;
    },
  },
});

모범 사례

  •         **변경이 필요하지 않은 경우 반환 `null` 합니다.** 빈 개체 또는 동일한 결과를 반환하는 것보다 더 효율적입니다.
    
  •         **결과 수정에 주의하세요.** 결과를 변경하면 모델이 도구 출력을 해석하는 방식에 영향을 줄 수 있습니다. 필요한 경우에만 수정합니다.
    
  •         **힌트에 사용합니다 `additionalContext` .** 결과를 수정하는 대신 모델이 해석하는 데 도움이 되는 컨텍스트를 추가합니다.
    
  •         **로깅할 때 개인 정보를 고려합니다.** 도구 결과에는 중요한 데이터가 포함될 수 있습니다. 로깅 전에 수정을 적용합니다.
    
  •         **후크가 빠르게 작동하도록 유지합니다.** 사후 툴 훅은 동기적으로 실행됩니다. 무거운 처리는 비동기적으로 수행하거나 일괄 처리해야 합니다.
    

추가 읽기

  •         [AUTOTITLE](/copilot/how-tos/copilot-sdk/use-hooks/quickstart)
    
  •         [AUTOTITLE](/copilot/how-tos/copilot-sdk/use-hooks/pre-tool-use)
    
  •         [AUTOTITLE](/copilot/how-tos/copilot-sdk/use-hooks/error-handling)