> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Session Hook

> 透過 SessionHooks 於 Copilot session 生命週期中插入處理，實作執行控制、稽核、復原邏輯。

## Session Hook

透過 `hooks` 可於 Copilot session 的各生命週期插入處理。
可在不改動核心實作的情況下，加入工具執行控制、稽核日誌、prompt 補強、錯誤處理等功能。

## Hook 流程

```mermaid theme={null}
flowchart LR
    A[Session starts] -->|onSessionStart| B[User prompt]
    B -->|onUserPromptSubmitted| C[Pre tool]
    C -->|onPreToolUse| D[Tool execution]
    D -->|onPostToolUse| E{Continue?}
    E -->|yes| C
    E -->|no| F[Session ends]
    F -->|onSessionEnd| G((Done))
    C -. error .-> H[onErrorOccurred]
    D -. error .-> H
```

## 基本用法

```php theme={null}
use Revolution\Copilot\Contracts\CopilotSession;
use Revolution\Copilot\Facades\Copilot;
use Revolution\Copilot\Types\SessionHooks;
use Revolution\Copilot\Types\Hooks\ErrorOccurredHookInput;
use Revolution\Copilot\Types\Hooks\ErrorOccurredHookOutput;
use Revolution\Copilot\Types\Hooks\PostToolUseHookInput;
use Revolution\Copilot\Types\Hooks\PostToolUseHookOutput;
use Revolution\Copilot\Types\Hooks\PreToolUseHookInput;
use Revolution\Copilot\Types\Hooks\PreToolUseHookOutput;
use Revolution\Copilot\Types\Hooks\SessionEndHookInput;
use Revolution\Copilot\Types\Hooks\SessionEndHookOutput;
use Revolution\Copilot\Types\Hooks\SessionStartHookInput;
use Revolution\Copilot\Types\Hooks\SessionStartHookOutput;
use Revolution\Copilot\Types\Hooks\UserPromptSubmittedHookInput;
use Revolution\Copilot\Types\Hooks\UserPromptSubmittedHookOutput;

Copilot::start(function (CopilotSession $session) {
    $response = $session->sendAndWait(prompt: '請摘要 README 的重點');
    dump($response->content());
}, config: [
    'model' => 'gpt-5',
    'hooks' => new SessionHooks(
        onSessionStart: function (SessionStartHookInput $input): ?SessionStartHookOutput {
            return new SessionStartHookOutput(
                additionalContext: "Project root: {$input->cwd}",
            );
        },

        onUserPromptSubmitted: function (UserPromptSubmittedHookInput $input): ?UserPromptSubmittedHookOutput {
            if (str_starts_with($input->prompt, '/fix')) {
                return new UserPromptSubmittedHookOutput(
                    modifiedPrompt: '請修正目前的錯誤，並摘要變更點。',
                );
            }

            return null;
        },

        onPreToolUse: function (PreToolUseHookInput $input): ?PreToolUseHookOutput {
            $blocked = ['bash', 'shell', 'delete_file'];

            if (in_array($input->toolName, $blocked, true)) {
                return new PreToolUseHookOutput(
                    permissionDecision: 'deny',
                    permissionDecisionReason: "{$input->toolName} 在此環境不被允許",
                );
            }

            return new PreToolUseHookOutput(permissionDecision: 'allow');
        },

        onPostToolUse: function (PostToolUseHookInput $input): ?PostToolUseHookOutput {
            if ($input->toolName === 'read_file') {
                return new PostToolUseHookOutput(
                    additionalContext: '如有需要請也探索相關檔案並比較。',
                );
            }

            return null;
        },

        onErrorOccurred: function (ErrorOccurredHookInput $input): ?ErrorOccurredHookOutput {
            if ($input->errorContext === 'model_call' && $input->recoverable) {
                return new ErrorOccurredHookOutput(
                    errorHandling: 'retry',
                    retryCount: 2,
                    userNotification: '因暫時性的模型錯誤將進行重試。',
                );
            }

            return null;
        },

        onSessionEnd: function (SessionEndHookInput $input): ?SessionEndHookOutput {
            if ($input->reason !== 'complete') {
                return new SessionEndHookOutput(
                    sessionSummary: "Session ended with reason: {$input->reason}",
                );
            }

            return null;
        },
    ),
]);
```

## 可用 hook

| Hook                    | 觸發時機                                     | 主要用途                    |
| ----------------------- | ---------------------------------------- | ----------------------- |
| `onSessionStart`        | Session 開始（`new` / `resume` / `startup`） | 注入初始脈絡、覆寫設定             |
| `onUserPromptSubmitted` | 使用者送出 prompt 時                           | Prompt 補強、範本展開、輸入過濾     |
| `onPreToolUse`          | 工具執行前                                    | 允許 / 拒絕 / 需確認、參數修改、輸出抑制 |
| `onPostToolUse`         | 工具執行後                                    | 結果修改、機密資訊遮罩、稽核日誌        |
| `onErrorOccurred`       | Session 內發生錯誤時                           | 重試、通知、錯誤分類              |
| `onSessionEnd`          | Session 結束時                              | 清理、指標、結束摘要              |

回傳 `null` 時會繼續預設行為。

## 常見的使用情境

### 1) Permission control（執行控制）

* 於 `onPreToolUse` 以 allow-list 方式管理允許的工具
* 破壞性操作以 `permissionDecision: 'ask'` 進行人為核准
* 以 `permissionDecisionReason` 明示拒絕原因
* `toolName` 的候選項可從 [Tools](/zh-TW/packages/laravel-copilot-sdk/tools) 的清單確認（如 `view`, `glob`, `bash`）

### 2) Auditing / compliance（稽核）

* 組合生命週期 hook 蒐集稽核事件
* 蒐集到的資料以 session ID 為單位持久化

### 3) Prompt enrichment（輸入補強）

* 於 `onSessionStart` 將專案資訊（語言、框架、規範）加入 `additionalContext`
* 於 `onUserPromptSubmitted` 展開捷徑（`/fix`, `/test`）

### 4) Result filtering（結果整理）

* 於 `onPostToolUse` 遮罩 API key / token / password 等
* 對過長結果進行摘要化，僅於需要時回傳細節

### 5) Error recovery（故障復原）

* 於 `onErrorOccurred` 僅當 `model_call` 且 `recoverable=true` 時執行 `retry`
* 對無法回復的錯誤，以 `userNotification` 簡潔通知使用者

### 6) Session metrics（度量）

* 於 `onSessionStart` 記錄開始時間
* 於 `onPreToolUse` / `onUserPromptSubmitted` 更新計數器
* 於 `onSessionEnd` 輸出耗時、工具次數、結束原因

## Hook input / output 型別

### 共用輸入（`BaseHookInput`）

| 屬性          | 型別       | 說明                 |
| ----------- | -------- | ------------------ |
| `timestamp` | `int`    | Hook 觸發時間（Unix ms） |
| `cwd`       | `string` | 目前工作目錄             |

### `PreToolUseHookInput`

| 屬性         | 型別       | 說明        |
| ---------- | -------- | --------- |
| `toolName` | `string` | 即將執行的工具名稱 |
| `toolArgs` | `mixed`  | 即將執行的參數   |

### `PreToolUseHookOutput`

| 屬性                         | 型別        | 說明                       |
| -------------------------- | --------- | ------------------------ |
| `permissionDecision`       | `?string` | `allow` / `deny` / `ask` |
| `permissionDecisionReason` | `?string` | 拒絕 / 確認時的理由              |
| `modifiedArgs`             | `mixed`   | 覆寫後的參數                   |
| `additionalContext`        | `?string` | 追加脈絡                     |
| `suppressOutput`           | `?bool`   | 抑制工具輸出                   |

### `PostToolUseHookInput`

| 屬性           | 型別                        | 說明      |
| ------------ | ------------------------- | ------- |
| `toolName`   | `string`                  | 已執行工具名稱 |
| `toolArgs`   | `mixed`                   | 執行時的參數  |
| `toolResult` | `ToolResultObject\|array` | 工具結果    |

### `PostToolUseHookOutput`

| 屬性                  | 型別                              | 說明       |
| ------------------- | ------------------------------- | -------- |
| `modifiedResult`    | `ToolResultObject\|array\|null` | 修改後的結果   |
| `additionalContext` | `?string`                       | 追加脈絡     |
| `suppressOutput`    | `?bool`                         | 抑制工具結果顯示 |

### `UserPromptSubmittedHookInput`

| 屬性       | 型別       | 說明            |
| -------- | -------- | ------------- |
| `prompt` | `string` | 使用者輸入的 prompt |

### `UserPromptSubmittedHookOutput`

| 屬性                  | 型別        | 說明          |
| ------------------- | --------- | ----------- |
| `modifiedPrompt`    | `?string` | 修改後的 prompt |
| `additionalContext` | `?string` | 補充脈絡        |
| `suppressOutput`    | `?bool`   | 抑制回應顯示      |

### `SessionStartHookInput`

| 屬性              | 型別        | 說明                           |
| --------------- | --------- | ---------------------------- |
| `source`        | `string`  | `startup` / `resume` / `new` |
| `initialPrompt` | `?string` | 初始 prompt                    |

### `SessionStartHookOutput`

| 屬性                  | 型別        | 說明              |
| ------------------- | --------- | --------------- |
| `additionalContext` | `?string` | Session 初始脈絡    |
| `modifiedConfig`    | `?array`  | Session 設定的部分覆寫 |

### `SessionEndHookInput`

| 屬性             | 型別        | 說明                                                       |
| -------------- | --------- | -------------------------------------------------------- |
| `reason`       | `string`  | `complete` / `error` / `abort` / `timeout` / `user_exit` |
| `finalMessage` | `?string` | 最終訊息                                                     |
| `error`        | `?string` | 結束時的錯誤                                                   |

### `SessionEndHookOutput`

| 屬性               | 型別        | 說明         |
| ---------------- | --------- | ---------- |
| `suppressOutput` | `?bool`   | 抑制最終輸出     |
| `cleanupActions` | `?array`  | 已執行的清理資訊   |
| `sessionSummary` | `?string` | Session 摘要 |

### `ErrorOccurredHookInput`

| 屬性             | 型別        | 說明                                                             |
| -------------- | --------- | -------------------------------------------------------------- |
| `error`        | `string`  | 錯誤訊息                                                           |
| `errorContext` | `?string` | `model_call` / `tool_execution` / `system` / `user_input` 其中之一 |
| `recoverable`  | `bool`    | 是否可回復                                                          |

### `ErrorOccurredHookOutput`

| 屬性                 | 型別        | 說明                         |
| ------------------ | --------- | -------------------------- |
| `suppressOutput`   | `?bool`   | 抑制錯誤顯示                     |
| `errorHandling`    | `?string` | `retry` / `skip` / `abort` |
| `retryCount`       | `?int`    | 重試次數                       |
| `userNotification` | `?string` | 對使用者的通知文字                  |

## ToolResultObject

工具執行結果的標準物件。

| 屬性                   | 型別        | 說明                                            |
| -------------------- | --------- | --------------------------------------------- |
| `textResultForLlm`   | `?string` | 交給 LLM 的文字結果                                  |
| `resultType`         | `?string` | `success` / `failure` / `rejected` / `denied` |
| `resultForAssistant` | `?array`  | 給助理的結果資料                                      |

## 最佳實踐

1. 不要在 hook 內直接執行過重的同步處理，如有必要請改為非同步。
2. 不需變更時回傳 `null`，交由預設行為。
3. 盡可能明確指定 `permissionDecision`。
4. 對關鍵錯誤不要過度抑制，保有日誌 / 通知的路徑。
5. Session 層級狀態以 session id 為基準管理，並於 `onSessionEnd` 清理。

<Info>
  最新資訊請參考 [GitHub 儲存庫](https://github.com/invokable/laravel-copilot-sdk)。
</Info>


## Related topics

- [Session 生命週期事件](/zh-TW/packages/laravel-copilot-sdk/session-lifecycle-event.md)
- [Agent Loop](/zh-TW/packages/laravel-copilot-sdk/agent-loop.md)
- [SessionConfig](/zh-TW/packages/laravel-copilot-sdk/session-config.md)
- [Plugin Directories](/zh-TW/packages/laravel-copilot-sdk/plugin-directories.md)
- [Session](/zh-TW/session.md)
