钩子系统
Agentrix 钩子系统允许您在关键生命周期节点拦截和定制代理行为。
钩子是什么?
钩子是在代理执行过程中特定时刻执行的 TypeScript 函数。它们使您能够:
- 控制工具执行 :在执行前批准、拒绝或修改工具调用
- 跟踪会话 : 监控代理生命周期事件
- 处理结果 : 检查和转换工具输出
- 添加自定义逻辑 : 注入特定领域的行为
快速示例
import type { PreToolUseHookInput } from '@anthropic-ai/claude-agent-sdk';
export async function PreToolUse(
input: PreToolUseHookInput,
toolUseID: string,
options: { signal: AbortSignal }
) {
// Block destructive operations
if (input.tool_name === 'Bash' &&
input.tool_input?.command?.includes('rm -rf')) {
return { decision: 'block', systemMessage: 'Destructive command blocked' };
}
return { decision: 'approve' };
}
可用钩子
Agentrix 支持 Claude SDK 钩子类型:
从 @anthropic-ai/claude-agent-sdk :
- PreToolUse - 在工具执行前
- PostToolUse - 在工具执行后
- SessionStart - 当代理会话开始时
- SessionEnd - 当代理会话结束时
- UserPromptSubmit - 当用户提交提示时
- Stop - 当代理停止时
- SubagentStart - 当子代理开始时
- SubagentStop - 当子代理停止时
- PreCompact - 在上下文压缩之前
- Notification - 系统通知
- PermissionRequest - 当需要权限时
钩子文档
按类别
工具控制 :
- 使用前工具 & 使用后工具 - 控制和监控工具执行
会话生命周期 :
- 会话钩子 - SessionStart, SessionEnd, UserPromptSubmit, Stop, SubagentStop
系统事件 :
全面指南
入门指南
1. 设置钩子项目
mkdir -p claude/hooks/src
cd claude/hooks
创建 package.json:
{
"name": "agent-hooks",
"version": "1.0.0",
"type": "module",
"scripts": {
"build": "tsc",
"dev": "tsc --watch"
},
"dependencies": {
"@agentrix/shared": "latest"
},
"devDependencies": {
"@anthropic-ai/claude-agent-sdk": "^0.1.30",
"@types/node": "^20.0.0",
"typescript": "^5.0.0"
}
}
2. 安装依赖
npm install
3. 创建钩子
创建 src/index.ts:
import type { PreToolUseHookInput } from '@anthropic-ai/claude-agent-sdk';
export async function PreToolUse(
input: PreToolUseHookInput,
toolUseID: string,
options: { signal: AbortSignal }
) {
console.log(`[PreToolUse] ${input.tool_name}`);
return { decision: 'approve' };
}
4. 构建
npm run build
请参考开发指南进行完整设置。
钩子执行顺序
当代理运行时,钩子按此顺序执行:
1. SessionStart
↓
2. UserPromptSubmit (for each user message)
↓
3. PreToolUse (for each tool call)
↓
4. [Tool Executes]
↓
5. PostToolUse (for each tool result)
↓
6. PreCompact (if context limit reached)
↓
7. Stop / SessionEnd (when session ends)
特殊钩子:
- SubagentStop:在子代理完成时运行
- Notification:由系统事件触发
常见模式
安全控制
export async function PreToolUse(input: PreToolUseHookInput) {
// Deny dangerous bash commands
if (input.tool_name === 'Bash') {
const cmd = input.tool_input?.command;
if (cmd?.match(/rm -rf|dd if=|mkfs/)) {
return { decision: 'deny', message: 'Unsafe command' };
}
}
return { decision: 'approve' };
}
审计日志
import { appendFileSync } from 'fs';
export async function PostToolUse(input: PostToolUseHookInput) {
const log = {
timestamp: new Date().toISOString(),
tool: input.tool_name,
success: !input.tool_response?.error
};
appendFileSync('audit.log', JSON.stringify(log) + '\n');
return {};
}
参见示例了解更多模式。
类型安全
Claude 钩子输入类型由 @anthropic-ai/claude-agent-sdk 提供:
import type {
PreToolUseHookInput,
PostToolUseHookInput,
SessionStartHookInput,
SessionEndHookInput,
UserPromptSubmitHookInput,
StopHookInput,
SubagentStartHookInput,
SubagentStopHookInput,
PreCompactHookInput,
NotificationHookInput,
PermissionRequestHookInput,
} from '@anthropic-ai/claude-agent-sdk';
最佳实践
- 错误处理 :钩子不应崩溃 - 用 try/catch 包裹
- 超时 : 钩子有 30 秒超时 - 保持它们快速
- 副作用 : 对文件系统操作要谨慎
- 日志记录 : 使用 console.log 进行调试(可在代理日志中查看)
- 类型安全 : 总是从
@agentrix/shared导入类型
调试钩子
启用详细日志记录
DEBUG=agentrix:hooks agentrix run --agent=./my-agent
检查钩子执行
export async function PreToolUse(input: PreToolUseHookInput) {
console.log('[DEBUG] PreToolUse called:', {
tool: input.tool_name,
input: input.tool_input
});
return { decision: 'approve' };
}
本地测试钩子
// test/hook.test.ts
import { PreToolUse } from '../src/index';
const mockInput = {
tool_name: 'Read',
tool_input: { file_path: 'test.txt' }
};
const result = await PreToolUse(mockInput, 'test-id', {
signal: new AbortController().signal
});
console.assert(result.decision === 'approve');
限制
- 钩子运行在隔离进程中(钩子之间没有共享状态)
- 每个钩子30秒超时
- 无法修改代理的基础系统提示
- 无法添加新工具(请使用 MCP 服务器)
从旧版钩子迁移
旧格式:
export function preToolUse(toolName: string, input: any) {
// ...
}
新格式:
import type { PreToolUseHookInput } from '@anthropic-ai/claude-agent-sdk';
export async function PreToolUse(
input: PreToolUseHookInput,
toolUseID: string,
options: { signal: AbortSignal }
) {
// ...
}