关于 Hedera Hook Creation
Hedera Hook Creation 是面向 Hedera Agent Kit 开发者的技能,指导创建围绕 BaseTool 生命周期运行的非阻塞钩子。内容涵盖生命周期阶段、类型化参数、Context 状态和注册方式,并区分钩子与用于阻止调用的策略。
主要功能
- 01说明 BaseTool 的四个钩子阶段
- 02介绍 AbstractHook 接口与参数类型
- 03展示钩子注册及 Context 状态用法
- 04提供多工具类型处理模式
- 05区分钩子与策略的职责
适用场景
- 01记录工具调用并生成审计轨迹
- 02统计调用次数或维护会话状态
- 03在工具执行阶段记录耗时
- 04为多个工具方法编写钩子逻辑
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ hedera-dev/ hedera-skills --skill hedera-hook-creation安装后在 Claude Code 中输入/hedera-hook-creation确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
examples/tx-timing-hook/index.tsreferences/hook-interface.mdlifecycle.md详细介绍
创建 Hedera Agent Kit 钩子
钩子是非阻塞扩展,会在 BaseTool 生命周期的各个阶段运行。它们会观察并丰富执行过程:记录调用、写入审计日志、跟踪指标、在 Context 上持久化状态。它们不会阻止工具执行——这由策略负责(参见 agent-kit-policy skill)。
钩子仅对扩展
BaseTool的工具触发。直接实现Tool接口而不扩展BaseTool的工具会完全绕过钩子系统。
何时编写钩子,何时编写策略
| 如果你想…… | 使用 |
|---|---|
| 记录/审计/跟踪工具调用 | 钩子 |
丰富 Context(计数器、会话状态) | 钩子 |
| 在条件成立时阻止调用发生 | 策略(参见 agent-kit-policy) |
| 拒绝特定工具方法 | 策略 |
内置钩子包括 HcsAuditTrailHook 和 HolAuditTrailHook(由 HCS 支持的审计日志)——两者都位于 @hashgraph/hedera-agent-kit/hooks。
7 阶段生命周期
BaseTool.execute() 的执行流程如下:
[1] preToolExecutionHook ← hook fires
[2] normalizeParams (tool internal)
[3] postParamsNormalizationHook ← hook fires
[4] coreAction (tool internal)
[5] postCoreActionHook ← hook fires
[6] secondaryAction (tool internal)
[7] postToolExecutionHook ← hook fires
钩子会在阶段 1、3、5、7 触发。它们不会在阶段 2、4、6 触发。
各阶段的完整参数形状请参见 references/lifecycle.md。
AbstractHook 契约
import { AbstractHook } from '@hashgraph/hedera-agent-kit';
export abstract class AbstractHook {
abstract name: string; // human-readable identifier
abstract description?: string; // what the hook does
abstract relevantTools: string[]; // tool methods this hook cares about
// Override only the stages you need; defaults are no-ops.
preToolExecutionHook(params, method): Promise<any>;
postParamsNormalizationHook(params, method): Promise<any>;
postCoreActionHook(params, method): Promise<any>;
postToolExecutionHook(params, method): Promise<any>;
}
重要:方法签名为 (params, method)——params 是四种类型化对象之一,而 context 位于其中(params.context)。它不是单独的第一个参数。
| 阶段 | 参数类型 | 重要字段 |
|---|---|---|
| 1 | PreToolExecutionParams | context、rawParams、client |
| 3 | PostParamsNormalizationParams | + normalisedParams |
| 5 | PostCoreActionParams | + coreActionResult |
| 7 | PostSecondaryActionParams | + toolResult |
骨架
import {
AbstractHook,
Context,
PreToolExecutionParams,
PostSecondaryActionParams,
} from '@hashgraph/hedera-agent-kit';
export class MyHook extends AbstractHook {
name = 'My Hook';
description = 'What this hook does, in one sentence';
relevantTools = ['transfer_hbar', 'create_token'];
async preToolExecutionHook(params: PreToolExecutionParams, method: string) {
if (!this.relevantTools.includes(method)) return;
// ... your pre-execution logic ...
// params.context, params.rawParams, params.client
}
async postToolExecutionHook(params: PostSecondaryActionParams, method: string) {
if (!this.relevantTools.includes(method)) return;
// params.toolResult is the final tool output
}
}
每个钩子方法的第一行都应按 relevantTools 进行筛选。工具包会为所有工具调用分发所有钩子——除非你据此采取操作,否则 relevantTools 仅供参考。
注册钩子
钩子添加到 Context.hooks 中。工具包会将该上下文传递给 BaseTool.execute(),由它在生命周期中分发钩子。
import { AgentMode } from '@hashgraph/hedera-agent-kit';
import { allCorePlugins } from '@hashgraph/hedera-agent-kit/plugins';
import { HederaLangchainToolkit } from '@hashgraph/hedera-agent-kit-langchain';
import { MyHook } from './my-hook';
const toolkit = new HederaLangchainToolkit({
client,
configuration: {
plugins: allCorePlugins,
context: {
mode: AgentMode.AUTONOMOUS,
hooks: [new MyHook()],
},
},
});
多个钩子可以共存——在每个阶段,它们会按数组顺序运行。策略(参见 agent-kit-policy)也是 AbstractHook 实例,并添加到同一数组中。
多工具类型化模式
钩子参数是泛型(any)——工具包无法推断各工具的类型,因为一个钩子可能面向多个具有不同架构的工具。以下是三种模式:
1. 通用逻辑
当钩子与参数无关时(例如统计调用次数、将整个负载记录为 JSON):
async postToolExecutionHook(params: PostSecondaryActionParams, method: string) {
console.log(`[${method}]`, JSON.stringify(params.rawParams));
}
2. 类型守卫(少量已知集合)
根据 method 使用 switch 分支,并通过类型断言或守卫缩小类型范围:
async postParamsNormalizationHook(
params: PostParamsNormalizationParams,
method: string,
) {
switch (method) {
case 'transfer_hbar':
case 'transfer_hbar_with_allowance': {
const p = params.normalisedParams as { transfers: Array<{ amount: number }> };
const total = p.transfers.reduce((s, t) => s + t.amount, 0);
console.log(`[${method}] total HBAR: ${total}`);
break;
}
}
}
3. 策略映射(可插拔的第三方工具)
在构造函数中接收 Record<string, (params: any) => SomeResult>。验证每个 additionalTool 都有对应策略;若缺少,则在构造时抛出错误。MaxRecipientsPolicy 就采用了这种模式。
Context 上的状态
整个 Agent 运行期间,params.context 都是同一个 Context 实例。可将其用作每个会话的临时存储区:
async preToolExecutionHook(params: PreToolExecutionParams, method: string) {
if (!this.relevantTools.includes(method)) return;
const counts = ((params.context as any).callCounts ??= {} as Record<string, number>);
counts[method] = (counts[method] ?? 0) + 1;
}
(Context 使用结构化类型;可通过类型断言附加临时状态。如果你要发布此钩子,请记录它写入的键。)
最佳实践
- 在每个方法开头按
relevantTools进行筛选——开销小且符合惯例 - 如果钩子执行 I/O(HCS 写入、HTTP),请使用
try/catch包装——钩子抛出异常会中止整个工具调用 - 保持钩子轻量——它们处于关键执行路径上
- 不要阻塞——如果需要停止执行,请编写策略
- 除非确有必要,否则不要修改
rawParams或normalisedParams;后续钩子会看到你的修改 - 使用
description记录副作用(HCS 主题写入、外部 API 调用),以便策略作者/Agent 操作者了解钩子的作用 - 为日志行添加标签
[<hook-name>],便于使用 grep 查找
资源
references/hook-interface.md— 完整的参数类型定义,以及全部四个钩子阶段references/lifecycle.md— 各项的触发时机,以及它们在BaseTool的normalizeParams/coreAction/secondaryAction周围的执行情况examples/tx-timing-hook/— 用于计时工具执行并记录耗时的最小钩子示例
常用导入
import {
AbstractHook,
Context,
PreToolExecutionParams,
PostParamsNormalizationParams,
PostCoreActionParams,
PostSecondaryActionParams,
} from '@hashgraph/hedera-agent-kit';
// Built-in implementations live in the /hooks subpath
import { HcsAuditTrailHook, HolAuditTrailHook } from '@hashgraph/hedera-agent-kit/hooks';