{"meta":{"title":"ツール使用後フック","intro":"onPostToolUse フックは、ツールが正常に実行された****後に呼び出されます。 これは次の目的で使用されます。","product":"GitHub Copilot","breadcrumbs":[{"href":"/ja/enterprise-cloud@latest/copilot","title":"GitHub Copilot"},{"href":"/ja/enterprise-cloud@latest/copilot/how-tos","title":"方法"},{"href":"/ja/enterprise-cloud@latest/copilot/how-tos/copilot-sdk","title":"Copilot SDK"},{"href":"/ja/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/hooks","title":"フックを使用する"},{"href":"/ja/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/hooks/post-tool-use","title":"ツール使用後"}],"documentType":"article"},"body":"# ツール使用後フック\n\nonPostToolUse フックは、ツールが正常に実行された****後に呼び出されます。 これは次の目的で使用されます。\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n* 変換またはフィルターツールの結果\n* 監査のためのログ ツールの実行\n* 結果に基づいてコンテキストを追加する\n* 会話からの結果を抑制する\n\n> ```\n>           **失敗バリアント** — `onPostToolUse` は、ツールの実行が成功した場合にのみ発生します。 \n> ```\n\n**failed** ツールの呼び出しを観察するには、`onPostToolUseFailure` (Python では `on_post_tool_use_failure`、Go/.NET では `OnPostToolUseFailure`、Rust では `on_post_tool_use_failure`) を登録します。 ハンドラーは、 `{ sessionId, toolName, toolArgs, error, timestamp, workingDirectory }` ( `error` フィールドはツールのエラー結果から抽出された文字列) を受け取り、 `{ additionalContext: string }` を返してモデルの追加のガイダンス (再試行ヒントなど) を挿入する場合があります。 完全な一覧については [、AUTOTITLE](/ja/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/hooks/hooks-overview) を参照してください。 <a id=\"failure-variant\"></a>\n\n## フック署名\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\ntype PostToolUseHandler = (\n  input: PostToolUseHookInput,\n  invocation: HookInvocation,\n) => Promise<PostToolUseHookOutput | null | undefined>;\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```python\nPostToolUseHandler = Callable[\n    [PostToolUseHookInput, dict[str, str]],\n    Awaitable[PostToolUseHookOutput | None]\n]\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n```golang\ntype PostToolUseHandler func(\n    input PostToolUseHookInput,\n    invocation HookInvocation,\n) (*PostToolUseHookOutput, error)\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n```csharp\npublic delegate Task<PostToolUseHookOutput?> PostToolUseHandler(\n    PostToolUseHookInput input,\n    HookInvocation invocation);\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n```java\n@FunctionalInterface\npublic interface PostToolUseHandler {\n    CompletableFuture<PostToolUseHookOutput> handle(\n        PostToolUseHookInput input,\n        HookInvocation invocation);\n}\n```\n\n</div>\n\n</div>\n\n## 入力\n\n| フィールド              | タイプ            | Description   |\n| ------------------ | -------------- | ------------- |\n| `timestamp`        | SDK タイムスタンプの種類 | フックがトリガーされたとき |\n| `workingDirectory` | 文字列            | 現在の作業ディレクトリ   |\n| `toolName`         | 文字列            | 呼び出されたツールの名前  |\n| `toolArgs`         | オブジェクト         | ツールに渡された引数    |\n| `toolResult`       | オブジェクト         | ツールによって返される結果 |\n\n## アウトプット\n\n結果を変更せずに渡す `null` または `undefined` を返します。 それ以外の場合は、次のいずれかのフィールドを持つオブジェクトを返します。\n\n| フィールド               | タイプ     | Description            |\n| ------------------- | ------- | ---------------------- |\n| `modifiedResult`    | オブジェクト  | 元の結果ではなく使用するように変更された結果 |\n| `additionalContext` | 文字列     | 会話に挿入された追加のコンテキスト      |\n| `suppressOutput`    | boolean | true、結果は会話に表示されません     |\n\n## 例\n\n### すべてのツールの結果をログに記録する\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\nconst session = await client.createSession({\n  hooks: {\n    onPostToolUse: async (input, invocation) => {\n      console.log(`[${invocation.sessionId}] Tool: ${input.toolName}`);\n      console.log(`  Args: ${JSON.stringify(input.toolArgs)}`);\n      console.log(`  Result: ${JSON.stringify(input.toolResult)}`);\n      return null; // Pass through unchanged\n    },\n  },\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```python\nfrom copilot.session import PermissionHandler\n\nasync def on_post_tool_use(input_data, invocation):\n    print(f\"[{invocation['session_id']}] Tool: {input_data['toolName']}\")\n    print(f\"  Args: {input_data['toolArgs']}\")\n    print(f\"  Result: {input_data['toolResult']}\")\n    return None  # Pass through unchanged\n\nsession = await client.create_session(on_permission_request=PermissionHandler.approve_all, hooks={\"on_post_tool_use\": on_post_tool_use})\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n```golang\nsession, _ := client.CreateSession(context.Background(), &copilot.SessionConfig{\n    Hooks: &copilot.SessionHooks{\n        OnPostToolUse: func(input copilot.PostToolUseHookInput, inv copilot.HookInvocation) (*copilot.PostToolUseHookOutput, error) {\n            fmt.Printf(\"[%s] Tool: %s\\n\", inv.SessionID, input.ToolName)\n            fmt.Printf(\"  Args: %v\\n\", input.ToolArgs)\n            fmt.Printf(\"  Result: %v\\n\", input.ToolResult)\n            return nil, nil\n        },\n    },\n})\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n```csharp\nvar session = await client.CreateSessionAsync(new SessionConfig\n{\n    Hooks = new SessionHooks\n    {\n        OnPostToolUse = (input, invocation) =>\n        {\n            Console.WriteLine($\"[{invocation.SessionId}] Tool: {input.ToolName}\");\n            Console.WriteLine($\"  Args: {input.ToolArgs}\");\n            Console.WriteLine($\"  Result: {input.ToolResult}\");\n            return Task.FromResult<PostToolUseHookOutput?>(null);\n        },\n    },\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n<!-- docs-validate: skip -->\n\n```java\nimport com.github.copilot.*;\nimport com.github.copilot.rpc.*;\nimport java.util.concurrent.CompletableFuture;\n\nvar hooks = new SessionHooks()\n    .setOnPostToolUse((input, invocation) -> {\n        System.out.println(\"[\" + invocation.getSessionId() + \"] Tool: \" + input.getToolName());\n        System.out.println(\"  Args: \" + input.getToolArgs());\n        System.out.println(\"  Result: \" + input.getToolResult());\n        return CompletableFuture.completedFuture(null);\n    });\n\nvar session = client.createSession(\n    new SessionConfig()\n        .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)\n        .setHooks(hooks)\n).get();\n```\n\n</div>\n\n</div>\n\n### 機密データを編集する\n\n```typescript\nconst SENSITIVE_PATTERNS = [\n  /api[_-]?key[\"\\s:=]+[\"']?[\\w-]+[\"']?/gi,\n  /password[\"\\s:=]+[\"']?[\\w-]+[\"']?/gi,\n  /secret[\"\\s:=]+[\"']?[\\w-]+[\"']?/gi,\n];\n\nconst session = await client.createSession({\n  hooks: {\n    onPostToolUse: async (input) => {\n      if (typeof input.toolResult === \"string\") {\n        let redacted = input.toolResult;\n        for (const pattern of SENSITIVE_PATTERNS) {\n          redacted = redacted.replace(pattern, \"[REDACTED]\");\n        }\n\n        if (redacted !== input.toolResult) {\n          return { modifiedResult: redacted };\n        }\n      }\n      return null;\n    },\n  },\n});\n```\n\n### 大きな結果を切り捨てる\n\n```typescript\nconst MAX_RESULT_LENGTH = 10000;\n\nconst session = await client.createSession({\n  hooks: {\n    onPostToolUse: async (input) => {\n      const resultStr = JSON.stringify(input.toolResult);\n\n      if (resultStr.length > MAX_RESULT_LENGTH) {\n        return {\n          modifiedResult: {\n            truncated: true,\n            originalLength: resultStr.length,\n            content: resultStr.substring(0, MAX_RESULT_LENGTH) + \"...\",\n          },\n          additionalContext: `Note: Result was truncated from ${resultStr.length} to ${MAX_RESULT_LENGTH} characters.`,\n        };\n      }\n      return null;\n    },\n  },\n});\n```\n\n### 結果に基づいてコンテキストを追加する\n\n```typescript\nconst session = await client.createSession({\n  hooks: {\n    onPostToolUse: async (input) => {\n      // If a file read returned an error, add helpful context\n      if (input.toolName === \"read_file\" && input.toolResult?.error) {\n        return {\n          additionalContext:\n            \"Tip: If the file doesn't exist, consider creating it or checking the path.\",\n        };\n      }\n\n      // If shell command failed, add debugging hint\n      if (input.toolName === \"shell\" && input.toolResult?.exitCode !== 0) {\n        return {\n          additionalContext:\n            \"The command failed. Check if required dependencies are installed.\",\n        };\n      }\n\n      return null;\n    },\n  },\n});\n```\n\n### エラースタックトレースをフィルタリングする\n\n```typescript\nconst session = await client.createSession({\n  hooks: {\n    onPostToolUse: async (input) => {\n      if (input.toolResult?.error && input.toolResult?.stack) {\n        // Remove internal stack trace details\n        return {\n          modifiedResult: {\n            error: input.toolResult.error,\n            // Keep only first 3 lines of stack\n            stack: input.toolResult.stack.split(\"\\n\").slice(0, 3).join(\"\\n\"),\n          },\n        };\n      }\n      return null;\n    },\n  },\n});\n```\n\n### コンプライアンスの監査証跡\n\n```typescript\ninterface AuditEntry {\n  timestamp: Date;\n  sessionId: string;\n  toolName: string;\n  args: unknown;\n  result: unknown;\n  success: boolean;\n}\n\nconst auditLog: AuditEntry[] = [];\n\nconst session = await client.createSession({\n  hooks: {\n    onPostToolUse: async (input, invocation) => {\n      auditLog.push({\n        timestamp: input.timestamp,\n        sessionId: invocation.sessionId,\n        toolName: input.toolName,\n        args: input.toolArgs,\n        result: input.toolResult,\n        success: !input.toolResult?.error,\n      });\n\n      // Optionally persist to database/file\n      await saveAuditLog(auditLog);\n\n      return null;\n    },\n  },\n});\n```\n\n### ノイズの多い結果を抑制する\n\n```typescript\nconst NOISY_TOOLS = [\"list_directory\", \"search_codebase\"];\n\nconst session = await client.createSession({\n  hooks: {\n    onPostToolUse: async (input) => {\n      if (NOISY_TOOLS.includes(input.toolName)) {\n        // Summarize instead of showing full result\n        const items = Array.isArray(input.toolResult)\n          ? input.toolResult\n          : input.toolResult?.items || [];\n\n        return {\n          modifiedResult: {\n            summary: `Found ${items.length} items`,\n            firstFew: items.slice(0, 5),\n          },\n        };\n      }\n      return null;\n    },\n  },\n});\n```\n\n## ベスト プラクティス\n\n1. **変更が不要な場合に `null` を返す** - これは、空のオブジェクトまたは同じ結果を返すよりも効率的です。\n\n2. **結果の変更には注意してください** 。 結果を変更すると、モデルがツールの出力を解釈する方法に影響する可能性があります。 必要な場合にのみ変更します。\n\n3. **ヒントに `additionalContext` を使用** する - 結果を変更する代わりに、モデルがそれらを解釈できるようにコンテキストを追加します。\n\n4. **ログ記録時にプライバシーを考慮する** - ツールの結果に機密データが含まれている可能性があります。 ログ記録の前に編集を適用します。\n\n5. **フックは高速に保つ** - ツール実行後のフックは同期実行されます。 大量の処理は、非同期またはバッチ処理で行う必要があります。\n\n## こちらも参照ください\n\n* [フックを使用する](/ja/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/hooks)\n* [ツール使用前のフック](/ja/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/hooks/pre-tool-use)\n* [エラー処理フック](/ja/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/hooks/error-handling)"}