Hooks 系统架构
Moltbot 的事件驱动钩子系统
概述
Hooks 系统是 Moltbot 的事件驱动扩展机制,允许在关键事件点(如命令执行、Agent 运行、工具调用等)注入自定义逻辑。支持目录发现和动态加载。
设计目标
- 事件驱动: 在关键生命周期点触发钩子
- 目录发现: 从 bundled、managed、workspace 目录自动发现钩子
- 动态加载: 支持热重载和缓存清理
- 类型安全: 钩子处理器有明确的类型定义
- 优雅降级: 钩子错误不影响主流程
钩子系统组成
Internal Hooks
文件: src/hooks/internal-hooks.ts
Internal Hooks 是通过代码注册的同步/异步处理器,用于核心系统扩展。
注册机制
export type InternalHookEventType = "command" | "session" | "agent" | "gateway";
export type InternalHookEvent = {
/** 事件类型 (command, session, agent, gateway) */
type: InternalHookEventType;
/** 特定动作 (e.g., 'new', 'reset', 'stop') */
action: string;
/** 关联的 session key */
sessionKey: string;
/** 事件特定的上下文 */
context: Record<string, unknown>;
/** 发生时间戳 */
timestamp: Date;
/** 钩子可以推送消息的数组 */
messages: string[];
};
export type InternalHookHandler = (event: InternalHookEvent) => Promise<void> | void;
注册函数
// 注册通用事件处理器
registerInternalHook('command', async (event) => {
console.log('Command:', event.action);
});
// 注册特定事件处理器
registerInternalHook('command:new', async (event) => {
await saveSessionToMemory(event);
});
// 触发钩子
await triggerInternalHook({
type: 'command',
action: 'new',
sessionKey: 'agent:main',
context: { ... },
timestamp: new Date(),
messages: [],
});
Directory-Based Hooks
钩子类型定义
文件: src/hooks/types.ts
export type Hook = {
name: string;
description: string;
source: "moltbot-bundled" | "moltbot-managed" | "moltbot-workspace" | "moltbot-plugin";
pluginId?: string;
filePath: string; // HOOK.md 路径
baseDir: string; // 包含钩子的目录
handlerPath: string; // handler 模块路径
};
export type MoltbotHookMetadata = {
always?: boolean; // 总是触发
hookKey?: string; // 钩子唯一键
emoji?: string; // Emoji 图标
homepage?: string; // 主页 URL
/** 处理的事件列表 */
events: string[];
/** 导出名称 (默认: "default") */
export?: string;
/** 支持的操作系统 */
os?: string[];
/** 依赖要求 */
requires?: {
bins?: string[];
anyBins?: string[];
env?: string[];
config?: string[];
};
/** 安装规范 */
install?: HookInstallSpec[];
};
钩子目录结构
钩子通过目录结构自动发现:
~/.clawdbot/
├── hooks/bundled/ # 内置钩子 (moltbot-bundled)
│ ├── BOOTSTRAP_HOOK.md
│ └── session-start/
│ ├── HOOK.md
│ └── handler.ts
├── hooks/managed/ # 托管钩子 (moltbot-managed)
│ └── ...
└── workspace/
└── .clawdbot/hooks/ # 工作空间钩子 (moltbot-workspace)
└── ...
钩子文件格式
HOOK.md (Frontmatter)
---
name: "My Hook"
description: "A custom hook for agent events"
events: ["agent_start", "tool_call"]
export: "default"
os: ["darwin", "linux"]
requires:
bins: ["git"]
env: ["MY_ENV_VAR"]
config: ["agents.defaults.model"]
always: false
emoji: "🔌"
---
Hook description and documentation here...
## Example
This hook demonstrates how to respond to agent events.
handler.ts
// 默认导出
export default async function handler(context: HookContext) {
console.log('Hook triggered:', context.event);
return { success: true, message: 'Hook executed' };
}
// 命名导出
export async function myHandler(context: HookContext) {
// ...
}
钩子加载流程
文件: src/hooks/loader.ts
loadWorkspaceHookEntries
export function loadWorkspaceHookEntries(
workspaceDir: string,
opts: { config: MoltbotConfig }
): HookEntry[] {
const paths = [
`${workspaceDir}/hooks/bundled`,
`${workspaceDir}/hooks/managed`,
`${workspaceDir}/.clawdbot/hooks`,
];
const entries: HookEntry[] = [];
for (const basePath of paths) {
const found = scanHooksDirectory(basePath);
entries.push(...found);
}
return entries;
}
钩子事件类型
事件类型完整列表
文件: src/hooks/internal-hooks.ts
// Command 事件
"command"
"command:new"
"command:reset"
"command:status"
"command:help"
// Session 事件
"session"
"session:start"
"session:end"
"session:reset"
// Agent 事件
"agent"
"agent:bootstrap"
"agent:start"
"agent:end"
"agent:tool_call"
"agent:tool_result"
// Gateway 事件
"gateway"
"gateway:start"
"gateway:stop"
"gateway:reload"
Agent Bootstrap 事件
export type AgentBootstrapHookContext = {
workspaceDir: string;
bootstrapFiles: WorkspaceBootstrapFile[];
cfg?: MoltbotConfig;
sessionKey?: string;
sessionId?: string;
agentId?: string;
};
export type AgentBootstrapHookEvent = InternalHookEvent & {
type: "agent";
action: "bootstrap";
context: AgentBootstrapHookContext;
};
钩子配置
配置结构
export type NormalizedHooksConfig = {
internal?: {
enabled: boolean; // 全局开关
handlers?: Array<{
module: string; // 模块路径
event: string; // 监听的事件
export?: string; // 导出名称 (默认: "default")
}>;
};
};
配置示例
{
hooks: {
internal: {
enabled: true,
handlers: [
{
module: "/path/to/my-hook.js",
event: "agent:start",
export: "onAgentStart"
}
]
}
}
}
钩子 eligibility 上下文
平台检测
文件: src/hooks/types.ts
export type HookEligibilityContext = {
remote?: {
platforms: string[]; // 支持的平台列表
hasBin: (bin: string) => boolean; // 检查二进制文件
hasAnyBin: (bins: string[]) => boolean; // 检查任一文件
note?: string;
};
};
检查示例
// 检查平台兼容性
if (metadata.os) {
const platform = process.platform;
if (!metadata.os.includes(platform)) {
return { eligible: false, reason: `Platform ${platform} not supported` };
}
}
// 检查二进制依赖
if (metadata.requires?.bins) {
for (const bin of metadata.requires.bins) {
if (!ctx.remote.hasBin(bin)) {
return { eligible: false, reason: `Missing binary: ${bin}` };
}
}
}
// 检查环境变量
if (metadata.requires?.env) {
for (const envVar of metadata.requires.env) {
if (!process.env[envVar]) {
return { eligible: false, reason: `Missing env var: ${envVar}` };
}
}
}
钩子生命周期
Internal Hooks
Directory-Based Hooks
钩子安装
HookInstallSpec
export type HookInstallSpec = {
id?: string;
kind: "bundled" | "npm" | "git";
label?: string;
package?: string;
repository?: string;
bins?: string[];
};
安装示例
---
name: "Git Hook"
description: "Git integration hook"
events: ["before_tool_call"]
requires:
bins: ["git"]
install:
- kind: "npm"
package: "simple-git"
---
This hook requires git to be installed and installs the simple-git package.
内置钩子
Gmail Hooks
文件: src/hooks/gmail.ts
// Gmail Pub/Sub 集成
export function setupGmailHooks(config: MoltbotConfig) {
registerInternalHook('hooks.gmail', async (event) => {
// 处理 Gmail 事件
});
}
Legacy Config Hooks
文件: src/hooks/soul-evil.ts
// 遗留配置迁移
export function registerLegacyHooks() {
registerInternalHook('legacy:config', async (event) => {
// 迁移遗留配置
});
}
错误处理
优雅降级
// 内置钩子错误处理
export async function triggerInternalHook(event: InternalHookEvent): Promise<void> {
const allHandlers = [...typeHandlers, ...specificHandlers];
if (allHandlers.length === 0) return;
for (const handler of allHandlers) {
try {
await handler(event);
} catch (err) {
console.error(
`Hook error [${event.type}:${event.action}]:`,
err instanceof Error ? err.message : String(err),
);
// 继续执行其他处理器
}
}
}
代码路径引用
| 功能 | 文件路径 |
|---|---|
| Internal Hooks | src/hooks/internal-hooks.ts |
| 钩子类型定义 | src/hooks/types.ts |
| 钩子加载器 | src/hooks/loader.ts |
| 钩子配置 | src/hooks/config.ts |
| 钩子验证 | src/hooks/frontmatter.ts |
| Gmail Hooks | src/hooks/gmail.ts |
| Gmail Setup Utils | src/hooks/gmail-setup-utils.ts |
| Legacy Hooks | src/hooks/soul-evil.ts |
| Workspace Hooks | src/hooks/workspace.ts |
| Hooks Status | src/hooks/hooks-status.ts |
| Hooks Install | src/hooks/install.ts |