# 세션 후크

후크를 사용하면 대화 수명 주기의 주요 지점에서 Copilot 세션의 동작을 가로채고 사용자 지정할 수 있습니다. 후크를 사용하여 다음을 수행합니다.

<!-- markdownlint-disable GHD046 GHD005 -->

<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->

* **제어 도구 실행** - 도구 호출 승인, 거부 또는 수정
* **결과 변환** - 처리하기 전에 도구 출력 수정
* **컨텍스트 추가** - 세션 시작 시 추가 정보 삽입
* **오류 처리** - 사용자 지정 오류 처리 구현
* **감사 및 로그** - 규정 준수를 위한 모든 상호 작용 추적

## 사용 가능한 후크

| 후크                                                                                   | Trigger             | 사용 사례            |
| ------------------------------------------------------------------------------------ | ------------------- | ---------------- |
| [사전 도구 사용 후크](/ko/copilot/how-tos/copilot-sdk/hooks/pre-tool-use)                    | 도구를 실행하기 전에         | 권한 제어, 인수 유효성 검사 |
| [사후 도구 사용 후크](/ko/copilot/how-tos/copilot-sdk/hooks/post-tool-use)                   | 도구가 실행된 후(성공에만 해당)  | 결과 변환, 로깅        |
| [사후 도구 사용 후크](/ko/copilot/how-tos/copilot-sdk/hooks/post-tool-use#failure-variant)   | 도구 실행 후 결과가 실패했습니다. | 재시도 지침 삽입, 로그 오류 |
| [사용자 프롬프트 제출 후크](/ko/copilot/how-tos/copilot-sdk/hooks/user-prompt-submitted)        | 사용자가 메시지를 보내는 경우    | 프롬프트 수정, 필터링     |
| [세션 수명 주기 후크](/ko/copilot/how-tos/copilot-sdk/hooks/session-lifecycle#session-start) | 세션 시작               | 컨텍스트 추가, 세션 구성   |
| [세션 수명 주기 후크](/ko/copilot/how-tos/copilot-sdk/hooks/session-lifecycle#session-end)   | 세션 종료               | 정리, 분석           |
| [오류 처리 후크](/ko/copilot/how-tos/copilot-sdk/hooks/error-handling)                     | 오류가 발생합니다.          | 사용자 지정 오류 처리     |

## 빠른 시작

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

```typescript
import { CopilotClient } from "@github/copilot-sdk";

const client = new CopilotClient();

const session = await client.createSession({
  hooks: {
    onPreToolUse: async (input) => {
      console.log(`Tool called: ${input.toolName}`);
      // Allow all tools
      return { permissionDecision: "allow" };
    },
    onPostToolUse: async (input) => {
      console.log(`Tool result: ${JSON.stringify(input.toolResult)}`);
      return null; // No modifications
    },
    onSessionStart: async (input) => {
      return { additionalContext: "User prefers concise answers." };
    },
  },
});
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

```python
from copilot import CopilotClient
from copilot.session import PermissionHandler

async def main():
    client = CopilotClient()
    await client.start()

    async def on_pre_tool_use(input_data, invocation):
        print(f"Tool called: {input_data['toolName']}")
        return {"permissionDecision": "allow"}

    async def on_post_tool_use(input_data, invocation):
        print(f"Tool result: {input_data['toolResult']}")
        return None

    async def on_session_start(input_data, invocation):
        return {"additionalContext": "User prefers concise answers."}

    session = await client.create_session(on_permission_request=PermissionHandler.approve_all, hooks={
            "on_pre_tool_use": on_pre_tool_use,
            "on_post_tool_use": on_post_tool_use,
            "on_session_start": on_session_start,
        })
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

```golang
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{
        Hooks: &copilot.SessionHooks{
            OnPreToolUse: func(input copilot.PreToolUseHookInput, inv copilot.HookInvocation) (*copilot.PreToolUseHookOutput, error) {
                fmt.Printf("Tool called: %s\n", input.ToolName)
                return &copilot.PreToolUseHookOutput{
                    PermissionDecision: "allow",
                }, nil
            },
            OnPostToolUse: func(input copilot.PostToolUseHookInput, inv copilot.HookInvocation) (*copilot.PostToolUseHookOutput, error) {
                fmt.Printf("Tool result: %v\n", input.ToolResult)
                return nil, nil
            },
            OnSessionStart: func(input copilot.SessionStartHookInput, inv copilot.HookInvocation) (*copilot.SessionStartHookOutput, error) {
                return &copilot.SessionStartHookOutput{
                    AdditionalContext: "User prefers concise answers.",
                }, nil
            },
        },
    })
    _ = session
}
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

```csharp
using GitHub.Copilot;

var client = new CopilotClient();

var session = await client.CreateSessionAsync(new SessionConfig
{
    Hooks = new SessionHooks
    {
        OnPreToolUse = (input, invocation) =>
        {
            Console.WriteLine($"Tool called: {input.ToolName}");
            return Task.FromResult<PreToolUseHookOutput?>(
                new PreToolUseHookOutput { PermissionDecision = "allow" }
            );
        },
        OnPostToolUse = (input, invocation) =>
        {
            Console.WriteLine($"Tool result: {input.ToolResult}");
            return Task.FromResult<PostToolUseHookOutput?>(null);
        },
        OnSessionStart = (input, invocation) =>
        {
            return Task.FromResult<SessionStartHookOutput?>(
                new SessionStartHookOutput { AdditionalContext = "User prefers concise answers." }
            );
        },
    },
});
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

```java
import com.github.copilot.sdk.*;
import com.github.copilot.sdk.json.*;
import java.util.concurrent.CompletableFuture;

try (var client = new CopilotClient()) {
    client.start().get();

    var hooks = new SessionHooks()
        .setOnPreToolUse((input, invocation) -> {
            System.out.println("Tool called: " + input.getToolName());
            return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
        })
        .setOnPostToolUse((input, invocation) -> {
            System.out.println("Tool result: " + input.getToolResult());
            return CompletableFuture.completedFuture(null);
        })
        .setOnSessionStart((input, invocation) -> {
            return CompletableFuture.completedFuture(
                new SessionStartHookOutput("User prefers concise answers.", null)
            );
        });

    var session = client.createSession(
        new SessionConfig()
            .setHooks(hooks)
            .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
    ).get();
}
```

</div>

</div>

## 후크 호출 컨텍스트

모든 후크는 현재 세션에 대한 컨텍스트가 있는 매개 변수를 받 `invocation` 습니다.

| Field       | Type   | 설명        |
| ----------- | ------ | --------- |
| `sessionId` | string | 현재 세션의 ID |

이렇게 하면 후크가 상태를 유지 관리하거나 세션별 논리를 수행할 수 있습니다.

## 일반적인 패턴

### 모든 도구 호출 로깅

```typescript
const session = await client.createSession({
  hooks: {
    onPreToolUse: async (input) => {
      console.log(`[${new Date().toISOString()}] Tool: ${input.toolName}, Args: ${JSON.stringify(input.toolArgs)}`);
      return { permissionDecision: "allow" };
    },
    onPostToolUse: async (input) => {
      console.log(`[${new Date().toISOString()}] Result: ${JSON.stringify(input.toolResult)}`);
      return null;
    },
  },
});
```

### 위험한 도구 차단

```typescript
const BLOCKED_TOOLS = ["shell", "bash", "exec"];

const session = await client.createSession({
  hooks: {
    onPreToolUse: async (input) => {
      if (BLOCKED_TOOLS.includes(input.toolName)) {
        return {
          permissionDecision: "deny",
          permissionDecisionReason: "Shell access is not permitted",
        };
      }
      return { permissionDecision: "allow" };
    },
  },
});
```

### 사용자 컨텍스트 추가

```typescript
const session = await client.createSession({
  hooks: {
    onSessionStart: async () => {
      const userPrefs = await loadUserPreferences();
      return {
        additionalContext: `User preferences: ${JSON.stringify(userPrefs)}`,
      };
    },
  },
});
```

## 후크 가이드

* **[사전 도구 사용 후크](/ko/copilot/how-tos/copilot-sdk/hooks/pre-tool-use)** - 컨트롤 도구 실행 권한
* **[사후 도구 사용 후크](/ko/copilot/how-tos/copilot-sdk/hooks/post-tool-use)** - 도구 결과 변환
* **[사용자 프롬프트 제출 후크](/ko/copilot/how-tos/copilot-sdk/hooks/user-prompt-submitted)** - 사용자 프롬프트 수정
* **[세션 수명 주기 후크](/ko/copilot/how-tos/copilot-sdk/hooks/session-lifecycle)** - 세션 시작 및 종료
* **[오류 처리 후크](/ko/copilot/how-tos/copilot-sdk/hooks/error-handling)** - 사용자 지정 오류 처리

## 참고하십시오

* [첫 번째 Copilot 기반 앱 빌드](/ko/copilot/how-tos/copilot-sdk/getting-started)
* [첫 번째 Copilot 기반 앱 빌드](/ko/copilot/how-tos/copilot-sdk/getting-started#step-4-add-a-custom-tool)
* [디버깅 가이드](/ko/copilot/how-tos/copilot-sdk/troubleshooting/debugging)