Skip to main content

ツール使用前のフック

          `onPreToolUse`でツールを実行する前に、Copilot SDK フックを使用して、ツールの実行の制御、引数の変更、コンテキストの追加を行います。

この機能を使用できるユーザーについて

GitHub Copilot SDK は、すべての Copilot プランで使用できます。

メモ

Copilot SDK は現在 テクニカル プレビューです。 機能と可用性は変更される場合があります。

          `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 | 文字列 | ユーザーに表示される説明 (deny/ask) | | modifiedArgs | オブジェクト | ツールに渡す引数を変更しました | | additionalContext | 文字列 | 会話に挿入された追加のコンテキスト | | suppressOutput | ブーリアン | true、ツールの出力は会話に表示されません |

アクセス許可の決定

意思決定行動
"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)