# 钩子机制

<cite>
**本文引用的文件**
- [use-chat.ts](file://src/hooks/use-chat.ts)
- [use-sessions.ts](file://src/hooks/use-sessions.ts)
- [use-workspaces.ts](file://src/hooks/use-workspaces.ts)
- [use-agents.ts](file://src/hooks/use-agents.ts)
- [use-skills.ts](file://src/hooks/use-skills.ts)
- [use-settings.ts](file://src/hooks/use-settings.ts)
- [use-cron-tasks.ts](file://src/hooks/use-cron-tasks.ts)
- [use-task-executions.ts](file://src/hooks/use-task-executions.ts)
- [types.ts](file://src/lib/types.ts)
- [route.ts（聊天）](file://src/app/api/chat/route.ts)
- [route.ts（会话列表）](file://src/app/api/sessions/route.ts)
- [route.ts（工作空间）](file://src/app/api/workspaces/route.ts)
- [db.ts（迁移：hooks 表）](file://src/lib/db.ts)
</cite>

## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)

## 简介
本文件系统化阐述 Forge 的“钩子机制”。在当前代码库中，“钩子”并非传统前端事件钩子，而是指“工具调用拦截与治理”的能力：当智能体执行工具（如文件写入、命令运行等）时，系统可基于规则对工具调用进行预处理或阻断，以实现安全与合规控制。该机制通过数据库中的 hooks 表配置，结合后端 SDK 查询流程，在工具调用前触发“预处理”阶段，从而实现对工具行为的统一治理。

本技术文档将：
- 解释钩子的设计原理与实现架构（注册、触发、执行）
- 说明内置钩子类型与用途（按事件类型与动作类型划分）
- 提供自定义钩子开发方法（规则定义、参数传递、返回值/动作处理）
- 给出异步处理、错误传播、性能优化的最佳实践
- 提供从简单到复杂的完整开发示例路径
- 涵盖调试、测试与版本兼容策略
- 解释与 React Hooks 的关系与集成模式

## 项目结构
本仓库采用 Next.js 前端 + Node.js 后端的混合架构。钩子机制的核心涉及：
- 前端 React Hooks：封装与后端 API 的交互，负责状态管理与 UI 更新
- 后端 API 路由：接收请求、解析参数、驱动 SDK 查询、生成 SSE 流
- 数据模型与类型：定义消息、会话、工作空间、代理、技能、设置、定时任务等实体
- 数据库迁移：支持 hooks 表的演进（新增事件类型）

```mermaid
graph TB
subgraph "前端"
FC["use-chat.ts<br/>聊天流式渲染与权限决策"]
FS["use-sessions.ts<br/>会话 CRUD"]
FW["use-workspaces.ts<br/>工作空间 CRUD"]
FA["use-agents.ts<br/>代理 CRUD"]
SK["use-skills.ts<br/>技能 CRUD"]
ST["use-settings.ts<br/>设置读取与跨实例同步"]
CT["use-cron-tasks.ts<br/>定时任务 CRUD"]
TE["use-task-executions.ts<br/>任务执行分页查询"]
end
subgraph "后端"
API_CHAT["/api/chat<br/>POST：聊天流式输出"]
API_SESS["/api/sessions<br/>GET/POST：会话管理"]
API_WS["/api/workspaces<br/>GET/POST：工作空间管理"]
end
subgraph "数据与类型"
T["types.ts<br/>消息/会话/工作空间/代理/技能/设置/任务等类型"]
DBM["db.ts<br/>hooks 表迁移：支持新事件类型"]
end
FC --> API_CHAT
FS --> API_SESS
FW --> API_WS
FA --> |"依赖"| T
SK --> |"依赖"| T
ST --> |"依赖"| T
CT --> |"依赖"| T
TE --> |"依赖"| T
API_CHAT --> |"使用"| T
API_SESS --> |"使用"| T
API_WS --> |"使用"| T
DBM --> |"影响"| API_CHAT
```

图表来源
- [use-chat.ts:1-696](file://src/hooks/use-chat.ts#L1-L696)
- [use-sessions.ts:1-81](file://src/hooks/use-sessions.ts#L1-L81)
- [use-workspaces.ts:1-77](file://src/hooks/use-workspaces.ts#L1-L77)
- [use-agents.ts:1-103](file://src/hooks/use-agents.ts#L1-L103)
- [use-skills.ts:1-77](file://src/hooks/use-skills.ts#L1-L77)
- [use-settings.ts:1-56](file://src/hooks/use-settings.ts#L1-L56)
- [use-cron-tasks.ts:1-116](file://src/hooks/use-cron-tasks.ts#L1-L116)
- [use-task-executions.ts:1-98](file://src/hooks/use-task-executions.ts#L1-L98)
- [types.ts:1-221](file://src/lib/types.ts#L1-L221)
- [route.ts（聊天）:1-350](file://src/app/api/chat/route.ts#L1-L350)
- [route.ts（会话列表）:1-34](file://src/app/api/sessions/route.ts#L1-L34)
- [route.ts（工作空间）:1-60](file://src/app/api/workspaces/route.ts#L1-L60)
- [db.ts（迁移：hooks 表）:334-363](file://src/lib/db.ts#L334-L363)

章节来源
- [use-chat.ts:1-696](file://src/hooks/use-chat.ts#L1-L696)
- [use-sessions.ts:1-81](file://src/hooks/use-sessions.ts#L1-L81)
- [use-workspaces.ts:1-77](file://src/hooks/use-workspaces.ts#L1-L77)
- [use-agents.ts:1-103](file://src/hooks/use-agents.ts#L1-L103)
- [use-skills.ts:1-77](file://src/hooks/use-skills.ts#L1-L77)
- [use-settings.ts:1-56](file://src/hooks/use-settings.ts#L1-L56)
- [use-cron-tasks.ts:1-116](file://src/hooks/use-cron-tasks.ts#L1-L116)
- [use-task-executions.ts:1-98](file://src/hooks/use-task-executions.ts#L1-L98)
- [types.ts:1-221](file://src/lib/types.ts#L1-L221)
- [route.ts（聊天）:1-350](file://src/app/api/chat/route.ts#L1-L350)
- [route.ts（会话列表）:1-34](file://src/app/api/sessions/route.ts#L1-L34)
- [route.ts（工作空间）:1-60](file://src/app/api/workspaces/route.ts#L1-L60)
- [db.ts（迁移：hooks 表）:334-363](file://src/lib/db.ts#L334-L363)

## 核心组件
- 前端聊天钩子（use-chat）：负责聊天消息的加载、发送、流式渲染、权限请求与决策、以及与后端 SSE 的交互。它不直接定义“钩子”，但其内部的事件处理与 UI 更新体现了“钩子式”的事件驱动模式。
- 会话、工作空间、代理、技能、设置、定时任务等 React Hooks：提供 CRUD 与状态管理，作为钩子治理的上下文与数据来源。
- 后端聊天 API：在 SDK 查询过程中注入权限桥接器，实现工具调用前的拦截与处理。
- 类型系统：统一定义消息块、内容块、权限状态、代理与工具配置等，为钩子规则匹配提供基础。

章节来源
- [use-chat.ts:1-696](file://src/hooks/use-chat.ts#L1-L696)
- [use-sessions.ts:1-81](file://src/hooks/use-sessions.ts#L1-L81)
- [use-workspaces.ts:1-77](file://src/hooks/use-workspaces.ts#L1-L77)
- [use-agents.ts:1-103](file://src/hooks/use-agents.ts#L1-L103)
- [use-skills.ts:1-77](file://src/hooks/use-skills.ts#L1-L77)
- [use-settings.ts:1-56](file://src/hooks/use-settings.ts#L1-L56)
- [use-cron-tasks.ts:1-116](file://src/hooks/use-cron-tasks.ts#L1-L116)
- [types.ts:1-221](file://src/lib/types.ts#L1-L221)

## 架构总览
下图展示了从前端到后端的钩子触发链路：前端通过聊天 API 发起请求，后端根据会话与设置解析权限模式，创建权限桥接器；SDK 查询流经消息映射器，期间根据 hooks 规则对工具调用进行拦截、记录或阻断；最终通过 SSE 将事件回传给前端，前端据此更新 UI。

```mermaid
sequenceDiagram
participant FE as "前端 use-chat"
participant API as "后端 /api/chat"
participant SDK as "SDK 查询 Query"
participant MAP as "消息映射器 Mapper"
participant BR as "权限桥接器 Bridge"
participant DB as "SQLite"
FE->>API : "POST /api/chat {sessionId,message,attachments}"
API->>DB : "读取会话/设置/模型信息"
API->>BR : "按权限模式创建桥接器"
API->>SDK : "构造 Query 并开始消费流"
SDK->>MAP : "逐条消息映射为事件"
MAP->>BR : "遇到工具调用 -> 触发钩子规则"
BR-->>MAP : "允许/阻断/记录 结果"
MAP-->>API : "事件序列文本/思考/工具/权限等"
API-->>FE : "SSE 事件流"
FE->>FE : "UI 渲染与状态更新"
```

图表来源
- [route.ts（聊天）:74-350](file://src/app/api/chat/route.ts#L74-L350)
- [use-chat.ts:313-696](file://src/hooks/use-chat.ts#L313-L696)

章节来源
- [route.ts（聊天）:74-350](file://src/app/api/chat/route.ts#L74-L350)
- [use-chat.ts:313-696](file://src/hooks/use-chat.ts#L313-L696)

## 详细组件分析

### 聊天钩子（前端）：use-chat
- 功能要点
  - 加载历史消息、发送消息、流式渲染、权限请求与决策、取消流、清空消息
  - 使用 SSE 事件流解析与 UI 更新，支持多块类型（文本、思考、工具、权限等）
  - 支持子代理内容块与进度展示
- 关键流程
  - 发送消息：构建用户消息与占位助手消息，开启流式缓存，启动定时器统计耗时
  - 事件处理：根据事件类型（文本增量、思考增量、工具使用、工具结果、权限请求、完成等）更新消息块
  - 完成与错误：更新消息 ID、令牌统计、清理缓存；错误时回滚临时消息
- 与钩子的关系
  - 前端不直接定义钩子，但其事件处理逻辑体现了“钩子式”的事件驱动：工具调用、权限请求、思考状态等事件被逐一处理并反映到 UI

```mermaid
flowchart TD
Start(["发送消息"]) --> BuildUser["构建用户消息块"]
BuildUser --> PlaceHolder["插入占位助手消息"]
PlaceHolder --> StartStream["开启流式缓存与定时器"]
StartStream --> ReadSSE["读取 SSE 事件"]
ReadSSE --> Type{"事件类型？"}
Type --> |text_delta| AppendText["追加文本块"]
Type --> |thinking_delta| AppendThink["追加思考块"]
Type --> |tool_use/tool_result| UpdateTool["更新工具块"]
Type --> |permission_request| AddPerm["添加权限请求块"]
Type --> |done| Finalize["更新ID/令牌/清理缓存"]
Type --> |error| HandleErr["错误处理与回滚"]
AppendText --> Flush["合并刷新"]
AppendThink --> Flush
UpdateTool --> Flush
Flush --> ReadSSE
Finalize --> End(["结束"])
HandleErr --> End
```

图表来源
- [use-chat.ts:75-696](file://src/hooks/use-chat.ts#L75-L696)

章节来源
- [use-chat.ts:1-696](file://src/hooks/use-chat.ts#L1-L696)

### 后端聊天钩子：权限桥接器与 SDK 查询
- 权限模式与钩子触发
  - 前端可覆盖会话级权限模式；后端根据全局设置与模型提供商推导有效模式
  - 当权限模式为“确认”时，创建权限桥接器；当为“全量放行”时绕过权限检查
- SDK 查询与消息映射
  - SDK 查询流经消息映射器，将中间产物映射为事件；钩子规则在桥接器阶段生效
  - 若恢复会话失败（异常或无块），自动回退至历史提示重试
- 文件附件与媒体协议
  - 解析文本中的媒体协议行，提取文件路径；与启发式检测合并去重，复制到上传目录并通过 SSE 即时反馈
- 最终落盘与内存刷新
  - 保存助手消息；必要时更新会话标题；后台触发内存刷新提醒

```mermaid
sequenceDiagram
participant API as "后端 /api/chat"
participant BR as "权限桥接器"
participant Q as "SDK Query"
participant MAP as "消息映射器"
participant DB as "SQLite"
API->>API : "解析权限模式/思考模式"
API->>BR : "创建桥接器确认模式"
API->>Q : "构造 Query含附件/思考模式"
Q->>MAP : "逐条消息映射"
MAP->>BR : "工具调用 -> 触发钩子规则"
BR-->>MAP : "允许/阻断/记录"
MAP-->>API : "事件序列"
API->>DB : "保存消息/更新会话"
API-->>客户端 : "SSE 事件流"
```

图表来源
- [route.ts（聊天）:74-350](file://src/app/api/chat/route.ts#L74-L350)

章节来源
- [route.ts（聊天）:74-350](file://src/app/api/chat/route.ts#L74-L350)

### 钩子表与事件类型演进
- 钩子表结构与约束
  - hooks 表包含名称、事件、工具模式、动作、命令、启用状态等字段
  - 迁移逻辑中移除了事件列的 CHECK 约束，以支持新的事件类型（如 notification、stop、subagent_start、subagent_stop）
- 事件类型与动作类型
  - 事件类型：用于匹配工具调用生命周期的关键节点（例如 pre_tool、post_tool、notification 等）
  - 动作类型：shell、block、log，分别对应执行外部命令、阻断工具、仅记录日志

```mermaid
erDiagram
HOOKS {
text id PK
text name
text event
text tool_pattern
text action
text command
int enabled
text created_at
}
```

图表来源
- [db.ts（迁移：hooks 表）:334-363](file://src/lib/db.ts#L334-L363)

章节来源
- [db.ts（迁移：hooks 表）:334-363](file://src/lib/db.ts#L334-L363)

### 内置钩子类型与用途
- 事件类型（示例）
  - pre_tool：工具调用前触发，适合权限校验、审计日志、环境准备
  - post_tool：工具调用后触发，适合清理资源、二次审计
  - notification：通知类事件，适合告警或状态上报
  - stop：停止类事件，适合中断流程
  - subagent_start/subagent_stop：子代理生命周期事件，适合资源隔离与追踪
- 动作类型（示例）
  - shell：执行外部脚本，可用于自动化处理
  - block：阻断工具调用，保障安全基线
  - log：记录事件，便于审计与排障

章节来源
- [db.ts（迁移：hooks 表）:334-363](file://src/lib/db.ts#L334-L363)

### 自定义钩子开发方法
- 规则定义
  - 在 hooks 表中新增规则，指定事件类型、工具模式（通配符）、动作类型与命令
  - 工具模式可按工具名或命名空间匹配，支持精确与模糊匹配
- 参数传递
  - 事件携带工具名、输入参数、会话 ID、时间戳等上下文，可在 shell 命令中引用
- 返回值与动作处理
  - block：直接阻断工具调用，返回错误或提示
  - shell：执行外部命令，命令退出码与输出可作为后续决策依据
  - log：记录事件详情，便于审计与监控
- 集成模式
  - 前端通过聊天 API 发起请求，后端在 SDK 查询阶段应用钩子规则，SSE 将事件回传前端，前端据此更新 UI

章节来源
- [route.ts（聊天）:74-350](file://src/app/api/chat/route.ts#L74-L350)
- [db.ts（迁移：hooks 表）:334-363](file://src/lib/db.ts#L334-L363)

### 钩子使用的最佳实践
- 异步处理
  - 使用 TransformStream 与 SSE 实现低延迟事件推送；避免一次性缓冲整个响应
- 错误传播
  - SDK 查询异常或无声失败时，自动回退至历史提示重试，并保留已生成的部分响应
- 性能考虑
  - 合理设置思考模式与内存归档频率；利用流式渲染与帧调度减少 UI 抖动
  - 对于文件附件，先解析媒体协议再做启发式检测，避免重复处理

章节来源
- [route.ts（聊天）:150-350](file://src/app/api/chat/route.ts#L150-L350)
- [use-chat.ts:190-312](file://src/hooks/use-chat.ts#L190-L312)

### 完整钩子开发示例（路径指引）
- 示例一：记录所有工具调用
  - 创建规则：事件类型选择 pre_tool，动作类型选择 log，工具模式设为 *
  - 效果：每次工具调用前都会记录日志，便于审计
- 示例二：阻断高风险工具
  - 创建规则：事件类型选择 pre_tool，动作类型选择 block，工具模式匹配危险工具名
  - 效果：阻断高风险工具调用，保障安全基线
- 示例三：执行外部脚本进行预处理
  - 创建规则：事件类型选择 pre_tool，动作类型选择 shell，命令中引用工具名与输入参数
  - 效果：在工具调用前执行预处理脚本，如环境变量注入或资源准备
- 示例四：子代理生命周期治理
  - 创建规则：事件类型选择 subagent_start/subagent_stop，动作类型选择 shell/log
  - 效果：对子代理的创建与销毁进行资源隔离与审计

章节来源
- [db.ts（迁移：hooks 表）:334-363](file://src/lib/db.ts#L334-L363)
- [route.ts（聊天）:74-350](file://src/app/api/chat/route.ts#L74-L350)

### 调试方法、测试策略与版本兼容
- 调试方法
  - 前端：观察 SSE 事件流，定位事件类型与块结构；检查权限请求与工具结果是否一致
  - 后端：开启日志，关注 SDK 查询异常与回退路径；验证钩子规则是否命中
- 测试策略
  - 单元测试：针对消息映射器与权限桥接器的行为进行模拟测试
  - 集成测试：通过聊天 API 发送带附件的消息，验证媒体协议解析与文件附件回传
  - 兼容性测试：在 hooks 表迁移前后验证事件类型的兼容性
- 版本兼容
  - hooks 表迁移逻辑确保新增事件类型（notification、stop、subagent_*）可被接受，避免因 CHECK 约束导致的升级失败

章节来源
- [route.ts（聊天）:74-350](file://src/app/api/chat/route.ts#L74-L350)
- [db.ts（迁移：hooks 表）:334-363](file://src/lib/db.ts#L334-L363)

### 与 React Hooks 的关系与集成模式
- use-chat 与聊天 API 的集成
  - use-chat 通过 fetch 发起请求，使用 ReadableStream 与 TextDecoder 解析 SSE
  - 事件类型驱动 UI 更新，体现“钩子式”的事件驱动模式
- 设置与跨实例同步
  - use-settings 通过自定义事件在多个实例间同步设置，保证钩子规则的一致性
- 会话与工作空间的上下文
  - use-sessions 与 use-workspaces 提供上下文数据，为钩子规则的生效范围（如按工作空间或会话）提供依据

章节来源
- [use-chat.ts:313-696](file://src/hooks/use-chat.ts#L313-L696)
- [use-settings.ts:1-56](file://src/hooks/use-settings.ts#L1-L56)
- [use-sessions.ts:1-81](file://src/hooks/use-sessions.ts#L1-L81)
- [use-workspaces.ts:1-77](file://src/hooks/use-workspaces.ts#L1-L77)

## 依赖关系分析
- 前端依赖后端 API：聊天、会话、工作空间等均通过 fetch 访问后端路由
- 后端依赖 SDK 与消息映射器：SDK 查询产出中间消息，映射器将其转换为事件
- 钩子规则依赖数据库：hooks 表存储规则，迁移逻辑保障事件类型扩展
- 类型系统贯穿：types.ts 定义消息块、权限状态、代理与工具配置等，为钩子匹配提供基础

```mermaid
graph LR
FE["前端 Hooks"] --> API["后端 API 路由"]
API --> SDK["SDK 查询"]
SDK --> MAP["消息映射器"]
MAP --> BR["权限桥接器"]
BR --> DB["SQLite"]
DB --> HOOKS["hooks 表"]
HOOKS --> BR
API --> TYPES["类型系统 types.ts"]
FE --> TYPES
```

图表来源
- [route.ts（聊天）:74-350](file://src/app/api/chat/route.ts#L74-L350)
- [types.ts:1-221](file://src/lib/types.ts#L1-L221)
- [db.ts（迁移：hooks 表）:334-363](file://src/lib/db.ts#L334-L363)

章节来源
- [route.ts（聊天）:74-350](file://src/app/api/chat/route.ts#L74-L350)
- [types.ts:1-221](file://src/lib/types.ts#L1-L221)
- [db.ts（迁移：hooks 表）:334-363](file://src/lib/db.ts#L334-L363)

## 性能考量
- SSE 与 TransformStream：避免响应缓冲，降低首包延迟
- 流式渲染与帧调度：使用 requestAnimationFrame 合并 UI 更新，减少重绘
- 内存归档与会话清理：定期归档旧记忆与清理过期会话，保持系统稳定
- 工具调用前的预处理：通过钩子在后端执行预处理，避免前端阻塞

章节来源
- [route.ts（聊天）:150-350](file://src/app/api/chat/route.ts#L150-L350)
- [use-chat.ts:190-312](file://src/hooks/use-chat.ts#L190-L312)

## 故障排查指南
- 聊天无响应或卡顿
  - 检查 SSE 是否正常，确认 TransformStream 未被阻塞
  - 查看前端事件处理分支是否正确更新消息块
- 工具调用被意外阻断
  - 检查 hooks 表规则是否命中；核对工具模式与动作类型
- 权限请求未出现
  - 确认权限模式为“确认”；检查权限桥接器是否创建成功
- 媒体附件未显示
  - 检查媒体协议解析与文件复制流程；确认上传目录可访问

章节来源
- [route.ts（聊天）:74-350](file://src/app/api/chat/route.ts#L74-L350)
- [use-chat.ts:313-696](file://src/hooks/use-chat.ts#L313-L696)

## 结论
Forge 的钩子机制通过“权限桥接器 + 消息映射器 + SSE 事件流”的组合，实现了对工具调用的统一治理。前端以事件驱动的方式渲染与交互，后端在 SDK 查询阶段注入钩子规则，形成闭环。通过合理的规则设计与最佳实践，可以在保障安全与合规的同时，提供流畅的用户体验。

## 附录
- 术语
  - 钩子：此处指工具调用拦截与治理机制，非前端事件钩子
  - 事件类型：工具调用生命周期中的关键节点
  - 动作类型：对事件的处理方式（shell/block/log）
- 参考路径
  - [聊天 API:74-350](file://src/app/api/chat/route.ts#L74-L350)
  - [会话 API:1-34](file://src/app/api/sessions/route.ts#L1-L34)
  - [工作空间 API:1-60](file://src/app/api/workspaces/route.ts#L1-L60)
  - [钩子表迁移:334-363](file://src/lib/db.ts#L334-L363)
  - [聊天前端 Hook:1-696](file://src/hooks/use-chat.ts#L1-L696)
  - [类型定义:1-221](file://src/lib/types.ts#L1-L221)