SuperAPI AI 工具集

Hedera Hook Creation

智能体与模型

查看项目

更新于 10-15 18:15

技能介绍

Hedera Hook Creation

用途

Hooks 是围绕 BaseTool 生命周期运行的非阻塞扩展。它们观察并可丰富执行过程:记录调用、写入审计轨迹、跟踪指标、在 Context 上持久化状态。它们不会阻止工具执行——那是 policies 的职责(见 agent-kit-policy 技能)。

Hooks 仅对扩展 BaseTool 的工具触发。直接实现 Tool 接口而不扩展 BaseTool 的工具会完全绕过 hook 系统。

何时编写 hook 与 policy

  • 记录/审计/跟踪工具调用:Hook
  • 丰富 Context(计数器、会话状态):Hook
  • 当条件成立时阻止调用发生:Policy(见 agent-kit-policy)
  • 拒绝特定工具方法:Policy

内置 hooks 包括 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

Hooks 接入阶段 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)。它不是单独的第一个参数。

阶段 Params 类型 值得注意的字段
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
  }
}

每个 hook 方法的第一行应按 relevantTools 进行过滤。工具包会为所有工具调用分派所有 hooks——除非你据此行动,否则 relevantTools 只是信息性的。

注册 hooks

Hooks 放在 Context.hooks 上。工具包将该 context 贯穿传递到 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()],
    },
  },
});

多个 hooks 可以共存——它们在每个阶段按数组顺序运行。Policies(见 agent-kit-policy)也是 AbstractHook 实例,放在同一个数组中。

多工具类型模式

Hook 参数是泛型的(any)——工具包无法推断每个工具的类型,因为一个 hook 可以针对多个具有不同 schema 的工具。三种模式:

1. 通用逻辑

当 hook 与参数无关时(计数调用、将整个负载记录为 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 上的状态

params.context 是整个 agent 运行期间相同的 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 是结构化类型的;转换以附加临时状态。如果你发布该 hook,请记录你写入的键。)

最佳实践

  • 在每个方法顶部按 relevantTools 过滤——便宜且惯用
  • 如果 hook 执行 I/O(HCS 写入、HTTP),用 try/catch 包裹——抛出的 hook 会中止整个工具调用
  • 保持 hooks 轻量——它们位于热路径上
  • 不要阻塞——如果需要停止执行,请编写 policy
  • 除非确实有意为之,不要修改 rawParams 或 normalisedParams;后续 hooks 会看到你的更改
  • 使用 description 记录副作用(HCS topic 写入、外部 API 调用),以便 policy 作者/agent 操作者知道该 hook 做什么
  • 用 [<hook-name>] 标记日志行以便于 grep

资源

  • references/hook-interface.md——完整参数类型定义、全部四个 hook 阶段
  • references/lifecycle.md——在 BaseTool 的 normalizeParams/coreAction/secondaryAction 周围何时触发什么
  • examples/tx-timing-hook/——最小 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';

限制

  • Hooks 仅对扩展 BaseTool 的工具触发;直接实现 Tool 接口的工具会绕过 hook 系统。
  • Hooks 为非阻塞扩展,不能阻止工具执行;如需阻止执行需使用 policies。
  • Hook 参数为泛型,工具包无法推断每个工具的类型。