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

# 会话钩子

> 使用 SessionHooks 在 Copilot 会话的生命周期中插入处理，实现执行控制、审计与恢复逻辑。

## 会话钩子

使用 `hooks` 可以在 Copilot 会话的各个生命周期节点插入处理。
你可以在不修改核心实现的前提下，添加工具执行控制、审计日志、prompt 增强、错误处理等。

## 钩子流程

```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                    | 触发时机                               | 主要用途                    |
| ----------------------- | ---------------------------------- | ----------------------- |
| `onSessionStart`        | 会话开始（`new` / `resume` / `startup`） | 注入初始上下文、覆盖配置            |
| `onUserPromptSubmitted` | 用户 prompt 发送时                      | prompt 增强、模板展开、输入过滤     |
| `onPreToolUse`          | 工具执行前                              | 允许 / 拒绝 / 需确认、修改参数、抑制输出 |
| `onPostToolUse`         | 工具执行后                              | 修改结果、脱敏敏感信息、审计日志        |
| `onErrorOccurred`       | 会话内发生错误时                           | 重试、通知、错误分类              |
| `onSessionEnd`          | 会话结束时                              | 清理、指标、结束摘要              |

返回 `null` 时会继续默认行为。

## 典型用例

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

* 通过 `onPreToolUse` 用 allow-list 方式限制允许的工具
* 破坏性操作用 `permissionDecision: 'ask'` 请求人工确认
* 通过 `permissionDecisionReason` 明确拒绝理由
* `toolName` 的候选值请参考 [Tools](/zh/packages/laravel-copilot-sdk/tools) 的列表（例如 `view`、`glob`、`bash`）

### 2) Auditing / compliance（审计）

* 组合生命周期钩子收集审计事件
* 按 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`    | 钩子触发时间（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` | 会话初始上下文   |
| `modifiedConfig`    | `?array`  | 会话配置的部分覆盖 |

### `SessionEndHookInput`

| 属性             | 类型        | 说明                                                       |
| -------------- | --------- | -------------------------------------------------------- |
| `reason`       | `string`  | `complete` / `error` / `abort` / `timeout` / `user_exit` |
| `finalMessage` | `?string` | 最终消息                                                     |
| `error`        | `?string` | 结束时的错误                                                   |

### `SessionEndHookOutput`

| 属性               | 类型        | 说明      |
| ---------------- | --------- | ------- |
| `suppressOutput` | `?bool`   | 抑制最终输出  |
| `cleanupActions` | `?array`  | 执行的清理信息 |
| `sessionSummary` | `?string` | 会话摘要    |

### `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. 不要在钩子内直接执行过重的同步处理。如有必要请异步化。
2. 不需要修改时返回 `null`，交给默认行为处理。
3. 尽可能显式地设置 `permissionDecision`。
4. 关键错误不要过度抑制，请保留日志 / 通知通道。
5. 会话级状态请基于 session id 管理，并在 `onSessionEnd` 时清理。

<Info>
  最新信息请参考 [GitHub 仓库](https://github.com/invokable/laravel-copilot-sdk)。
</Info>


## Related topics

- [代理循环](/zh/packages/laravel-copilot-sdk/agent-loop.md)
- [会话恢复](/zh/packages/laravel-copilot-sdk/resume.md)
- [快速开始 - GitHub Copilot SDK for Laravel](/zh/packages/laravel-copilot-sdk/getting-started.md)
- [会话生命周期事件](/zh/packages/laravel-copilot-sdk/session-lifecycle-event.md)
- [⚡ Livewire 4 入门 —— 无需 JavaScript 也能做出响应式 UI](/zh/blog/livewire-introduction.md)
