- 変換またはフィルターツールの結果
- 監査のためのログ ツールの実行
- 結果に基づいてコンテキストを追加する
- 会話からの結果を抑制する
**失敗バリアント** — `onPostToolUse` は、ツールの実行が成功した場合にのみ発生します。
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 を参照してください。
フック署名
import type {
PostToolUseHookInput,
HookInvocation,
PostToolUseHookOutput,
} from "@github/copilot-sdk";
type PostToolUseHandler = (
input: PostToolUseHookInput,
invocation: HookInvocation,
) => Promise<PostToolUseHookOutput | null | undefined>;
type PostToolUseHandler = (
input: PostToolUseHookInput,
invocation: HookInvocation,
) => Promise<PostToolUseHookOutput | null | undefined>;
from copilot.session import PostToolUseHookInput, PostToolUseHookOutput
from typing import Callable, Awaitable
PostToolUseHandler = Callable[
[PostToolUseHookInput, dict[str, str]],
Awaitable[PostToolUseHookOutput | None]
]
PostToolUseHandler = Callable[
[PostToolUseHookInput, dict[str, str]],
Awaitable[PostToolUseHookOutput | None]
]
package main
import copilot "github.com/github/copilot-sdk/go"
type PostToolUseHandler func(
input copilot.PostToolUseHookInput,
invocation copilot.HookInvocation,
) (*copilot.PostToolUseHookOutput, error)
func main() {}
type PostToolUseHandler func(
input PostToolUseHookInput,
invocation HookInvocation,
) (*PostToolUseHookOutput, error)
using GitHub.Copilot;
public delegate Task<PostToolUseHookOutput?> PostToolUseHandler(
PostToolUseHookInput input,
HookInvocation invocation);
public delegate Task<PostToolUseHookOutput?> PostToolUseHandler(
PostToolUseHookInput input,
HookInvocation invocation);
import com.github.copilot.sdk.json.*;
PostToolUseHandler postToolUseHandler;
入力
| フィールド | タイプ | Description |
|---|---|---|
timestamp | SDK タイムスタンプの種類 | フックがトリガーされたとき |
workingDirectory | 文字列 | 現在の作業ディレクトリ |
toolName | 文字列 | 呼び出されたツールの名前 |
toolArgs | オブジェクト | ツールに渡された引数 |
toolResult | オブジェクト | ツールによって返される結果 |
アウトプット
結果を変更せずに渡す null または undefined を返します。 それ以外の場合は、次のいずれかのフィールドを持つオブジェクトを返します。
| フィールド | タイプ | Description |
|---|---|---|
modifiedResult | オブジェクト | 元の結果ではなく使用するように変更された結果 |
additionalContext | 文字列 | 会話に挿入された追加のコンテキスト |
suppressOutput | boolean | 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
},
},
});
from copilot.session import PermissionHandler
async def on_post_tool_use(input_data, invocation):
print(f"[{invocation['session_id']}] Tool: {input_data['toolName']}")
print(f" Args: {input_data['toolArgs']}")
print(f" Result: {input_data['toolResult']}")
return None # Pass through unchanged
session = await client.create_session(on_permission_request=PermissionHandler.approve_all, hooks={"on_post_tool_use": on_post_tool_use})
package main
import (
"context"
"fmt"
copilot "github.com/github/copilot-sdk/go"
)
func main() {
client := copilot.NewClient(nil)
session, _ := client.CreateSession(context.Background(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Hooks: &copilot.SessionHooks{
OnPostToolUse: func(input copilot.PostToolUseHookInput, inv copilot.HookInvocation) (*copilot.PostToolUseHookOutput, error) {
fmt.Printf("[%s] Tool: %s\n", inv.SessionID, input.ToolName)
fmt.Printf(" Args: %v\n", input.ToolArgs)
fmt.Printf(" Result: %v\n", input.ToolResult)
return nil, nil
},
},
})
_ = session
}
session, _ := client.CreateSession(context.Background(), &copilot.SessionConfig{
Hooks: &copilot.SessionHooks{
OnPostToolUse: func(input copilot.PostToolUseHookInput, inv copilot.HookInvocation) (*copilot.PostToolUseHookOutput, error) {
fmt.Printf("[%s] Tool: %s\n", inv.SessionID, input.ToolName)
fmt.Printf(" Args: %v\n", input.ToolArgs)
fmt.Printf(" Result: %v\n", input.ToolResult)
return nil, nil
},
},
})
using GitHub.Copilot;
public static class PostToolUseExample
{
public static async Task Main()
{
await using var client = new CopilotClient();
var session = await client.CreateSessionAsync(new SessionConfig
{
Hooks = new SessionHooks
{
OnPostToolUse = (input, invocation) =>
{
Console.WriteLine($"[{invocation.SessionId}] Tool: {input.ToolName}");
Console.WriteLine($" Args: {input.ToolArgs}");
Console.WriteLine($" Result: {input.ToolResult}");
return Task.FromResult<PostToolUseHookOutput?>(null);
},
},
});
}
}
var session = await client.CreateSessionAsync(new SessionConfig
{
Hooks = new SessionHooks
{
OnPostToolUse = (input, invocation) =>
{
Console.WriteLine($"[{invocation.SessionId}] Tool: {input.ToolName}");
Console.WriteLine($" Args: {input.ToolArgs}");
Console.WriteLine($" Result: {input.ToolResult}");
return Task.FromResult<PostToolUseHookOutput?>(null);
},
},
});
import com.github.copilot.sdk.*;
import com.github.copilot.sdk.json.*;
import java.util.concurrent.CompletableFuture;
var hooks = new SessionHooks()
.setOnPostToolUse((input, invocation) -> {
System.out.println("[" + invocation.getSessionId() + "] Tool: " + input.getToolName());
System.out.println(" Args: " + input.getToolArgs());
System.out.println(" Result: " + input.getToolResult());
return CompletableFuture.completedFuture(null);
});
var session = client.createSession(
new SessionConfig()
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
.setHooks(hooks)
).get();
機密データを編集する
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: Date;
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を使用 する - 結果を変更する代わりに、モデルがそれらを解釈できるようにコンテキストを追加します。 -
ログ記録時にプライバシーを考慮する - ツールの結果に機密データが含まれている可能性があります。 ログ記録の前に編集を適用します。
-
フックは高速に保つ - ツール実行後のフックは同期実行されます。 大量の処理は、非同期またはバッチ処理で行う必要があります。