agent-kit-plugin
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCreating Hedera Agent Kit Plugins
创建Hedera Agent Kit插件
This skill provides guidance for creating custom plugins that extend the Hedera Agent Kit. Plugins allow adding new tools for Hedera network interactions—token operations, account management, consensus service, smart contracts, and custom integrations.
本技能提供创建扩展Hedera Agent Kit的自定义插件的指导。插件允许添加用于Hedera网络交互的新工具——包括代币操作、账户管理、共识服务、智能合约以及自定义集成。
Quick Start
快速开始
To create a Hedera plugin in 5 steps:
- Install dependencies: Set up a TypeScript project with and
@hashgraph/hedera-agent-kit@hiero-ledger/sdk - Create plugin structure: Create an with the plugin definition and a
index.tsdirectorytools/ - Define tools: Each tool is a class extending — this opts the tool into the hooks/policies lifecycle
BaseTool - Export properly: Export the plugin object and tool name constants
- Register with agent: Import and pass the plugin in the toolkit array
configuration.plugins
只需5步即可创建Hedera插件:
- 安装依赖:创建一个TypeScript项目,安装和
@hashgraph/hedera-agent-kit@hiero-ledger/sdk - 创建插件结构:创建包含插件定义的文件和
index.ts目录tools/ - 定义工具:每个工具都是继承自的类——这样工具就可以接入钩子/策略生命周期
BaseTool - 正确导出:导出插件对象和工具名称常量
- 在Agent中注册:导入插件并将其添加到工具包的数组中
configuration.plugins
Plugin Interface
插件接口
Every Hedera plugin implements this interface from :
@hashgraph/hedera-agent-kittypescript
import { Plugin } from '@hashgraph/hedera-agent-kit';
export interface Plugin {
name: string; // Unique kebab-case identifier
version?: string; // Semantic version (e.g., "1.0.0")
description?: string; // Brief explanation of plugin purpose
tools: (context: Context) => Tool[]; // Factory returning tools
}The function receives a object containing network configuration and returns an array of objects. itself implements , so a subclass instance is a valid return value.
toolsContextToolBaseToolToolBaseTool每个Hedera插件都实现了中的这个接口:
@hashgraph/hedera-agent-kittypescript
import { Plugin } from '@hashgraph/hedera-agent-kit';
export interface Plugin {
name: string; // Unique kebab-case identifier
version?: string; // Semantic version (e.g., "1.0.0")
description?: string; // Brief explanation of plugin purpose
tools: (context: Context) => Tool[]; // Factory returning tools
}toolsContextToolBaseToolToolBaseToolBaseTool
BaseToolBaseTool
BaseToolTools are written as classes extending , which implements and runs a 7-stage lifecycle:
BaseToolTooltext
[1] preToolExecutionHook
[2] normalizeParams ← your logic
[3] postParamsNormalizationHook
[4] coreAction ← your logic
[5] postCoreActionHook
[6] secondaryAction ← your logic (skipped via shouldSecondaryAction for queries)
[7] postToolExecutionHookHooks and policies registered on the agent kit fire at stages 1, 3, 5, and 7 automatically — you never call them manually.
A subclass must provide:
| Member | Type | Notes |
|---|---|---|
| | Snake-case identifier with |
| | Human-readable display name |
| | LLM-facing description (typically built in the constructor from a prompt function) |
| | Zod schema for input validation |
| async | Stage 2 — resolve defaults, validate format |
| async | Stage 4 — build the transaction or perform the query |
| async | Stage 6 — sign/submit the transaction (no-op for queries) |
Optional overrides: , (return for query-only tools), , and the four hook methods.
outputParsershouldSecondaryActionfalsehandleError工具以继承的类的形式编写,实现了接口,并运行7阶段的生命周期:
BaseToolBaseToolTooltext
[1] preToolExecutionHook
[2] normalizeParams ← your logic
[3] postParamsNormalizationHook
[4] coreAction ← your logic
[5] postCoreActionHook
[6] secondaryAction ← your logic (skipped via shouldSecondaryAction for queries)
[7] postToolExecutionHook在Agent Kit上注册的钩子和策略会在第1、3、5、7阶段自动触发——你无需手动调用它们。
子类必须实现以下成员:
| 成员 | 类型 | 说明 |
|---|---|---|
| | 蛇形命名的标识符,以 |
| | 人类可读的显示名称 |
| | 面向LLM的描述(通常在构造函数中通过提示函数生成) |
| | 用于输入校验的Zod模式 |
| async | 第2阶段——解析默认值,校验格式 |
| async | 第4阶段——构建交易或执行查询 |
| async | 第6阶段——签名/提交交易(查询工具跳过此步骤) |
可选的重写项:、(仅查询工具返回)、以及四个钩子方法。
outputParsershouldSecondaryActionfalsehandleErrorTool Types
工具类型
Mutation tools — state-changing operations (token create/mint/transfer, account update, topic submit). builds the , calls . Use .
coreActionTransactionsecondaryActionhandleTransaction()transactionToolOutputParserQuery tools — read-only operations (token info, balances, mirror-node fetches). returns the result directly. Override to return . Use .
coreActionshouldSecondaryActionfalseuntypedQueryOutputParser变更工具(Mutation tools)——改变状态的操作(代币创建/铸造/转账、账户更新、主题提交)。构建,调用。使用。
coreActionTransactionsecondaryActionhandleTransaction()transactionToolOutputParser查询工具(Query tools)——只读操作(代币信息、余额、镜像节点查询)。直接返回结果。重写返回。使用。
coreActionshouldSecondaryActionfalseuntypedQueryOutputParserFile Structure Pattern
文件结构模式
Follow this structure for all Hedera plugins:
my-hedera-plugin/
├── index.ts # Plugin definition and exports
└── tools/
└── category/ # Group related tools
├── create-something.ts
└── get-something.ts所有Hedera插件请遵循以下结构:
my-hedera-plugin/
├── index.ts # Plugin definition and exports
└── tools/
└── category/ # Group related tools
├── create-something.ts
└── get-something.tsCreating a Tool
创建工具
Step 1: Define the Tool Constant
步骤1:定义工具常量
typescript
export const MY_TOOL_NAME = 'my_tool_name_tool';Use UPPER_SNAKE_CASE with suffix for the constant. The value should be lowercase snake_case.
_TOOLtypescript
export const MY_TOOL_NAME = 'my_tool_name_tool';常量使用大写下划线命名(UPPER_SNAKE_CASE),并以后缀结尾。常量值应为小写下划线形式(snake_case)。
_TOOLStep 2: Create the Prompt Function
步骤2:创建提示函数
typescript
const myToolPrompt = (context: Context = {}) => {
return `This tool does X on Hedera.
Parameters:
- param1 (str, required): Description of param1
- param2 (int, optional): Description of param2, defaults to 0`;
};typescript
const myToolPrompt = (context: Context = {}) => {
return `This tool does X on Hedera.
Parameters:
- param1 (str, required): Description of param1
- param2 (int, optional): Description of param2, defaults to 0`;
};Step 3: Define Parameters with Zod
步骤3:使用Zod定义参数
typescript
import { z } from 'zod';
const myToolParameters = (_context: Context = {}) => {
return z.object({
param1: z.string().describe('Description of param1'),
param2: z.number().optional().describe('Description of param2'),
});
};
type MyToolParams = z.infer<ReturnType<typeof myToolParameters>>;See for common Hedera parameter patterns.
references/zod-schema-patterns.mdtypescript
import { z } from 'zod';
const myToolParameters = (_context: Context = {}) => {
return z.object({
param1: z.string().describe('Description of param1'),
param2: z.number().optional().describe('Description of param2'),
});
};
type MyToolParams = z.infer<ReturnType<typeof myToolParameters>>;常见的Hedera参数模式请参考。
references/zod-schema-patterns.mdStep 4: Implement the BaseTool subclass (mutation example)
步骤4:实现BaseTool子类(变更工具示例)
typescript
import { Client, Status } from '@hiero-ledger/sdk';
import {
BaseTool,
Context,
handleTransaction,
RawTransactionResponse,
transactionToolOutputParser,
} from '@hashgraph/hedera-agent-kit';
const postProcess = (response: RawTransactionResponse) =>
`Operation completed.
Transaction ID: ${response.transactionId}`;
export class MyTool extends BaseTool<MyToolParams, MyToolParams> {
method = MY_TOOL_NAME;
name = 'My Tool Display Name';
description: string;
parameters: ReturnType<typeof myToolParameters>;
outputParser = transactionToolOutputParser;
constructor(context: Context) {
super();
this.description = myToolPrompt(context);
this.parameters = myToolParameters(context);
}
// Stage 2 — resolve defaults
async normalizeParams(params: MyToolParams) {
return params;
}
// Stage 4 — build the transaction (do not sign here)
async coreAction(params: MyToolParams, _context: Context, _client: Client) {
// return new SomeTransaction()...;
return undefined as any;
}
// Stage 6 — sign and submit
async secondaryAction(transaction: any, client: Client, context: Context) {
return handleTransaction(transaction, client, context, postProcess);
}
async handleError(error: unknown) {
const message = 'Failed to execute' + (error instanceof Error ? `: ${error.message}` : '');
console.error(`[${MY_TOOL_NAME}]`, message);
return { raw: { status: Status.InvalidTransaction, error: message }, humanMessage: message };
}
}typescript
import { Client, Status } from '@hiero-ledger/sdk';
import {
BaseTool,
Context,
handleTransaction,
RawTransactionResponse,
transactionToolOutputParser,
} from '@hashgraph/hedera-agent-kit';
const postProcess = (response: RawTransactionResponse) =>
`Operation completed.
Transaction ID: ${response.transactionId}`;
export class MyTool extends BaseTool<MyToolParams, MyToolParams> {
method = MY_TOOL_NAME;
name = 'My Tool Display Name';
description: string;
parameters: ReturnType<typeof myToolParameters>;
outputParser = transactionToolOutputParser;
constructor(context: Context) {
super();
this.description = myToolPrompt(context);
this.parameters = myToolParameters(context);
}
// Stage 2 — resolve defaults
async normalizeParams(params: MyToolParams) {
return params;
}
// Stage 4 — build the transaction (do not sign here)
async coreAction(params: MyToolParams, _context: Context, _client: Client) {
// return new SomeTransaction()...;
return undefined as any;
}
// Stage 6 — sign and submit
async secondaryAction(transaction: any, client: Client, context: Context) {
return handleTransaction(transaction, client, context, postProcess);
}
async handleError(error: unknown) {
const message = 'Failed to execute' + (error instanceof Error ? `: ${error.message}` : '');
console.error(`[${MY_TOOL_NAME}]`, message);
return { raw: { status: Status.InvalidTransaction, error: message }, humanMessage: message };
}
}Step 5: Export a Factory
步骤5:导出工厂函数
typescript
const tool = (context: Context): BaseTool => new MyTool(context);
export default tool;The factory pattern lets the plugin's function instantiate a fresh tool per request with the right context bound.
tools(context)typescript
const tool = (context: Context): BaseTool => new MyTool(context);
export default tool;工厂模式使得插件的函数可以为每个请求实例化一个新的、绑定了正确上下文的工具。
tools(context)Query-tool variant — skip stage 6
查询工具变体——跳过第6阶段
For read-only tools, override so the lifecycle stops after , and have pass the result through unchanged:
shouldSecondaryActioncoreActionsecondaryActiontypescript
export class MyQueryTool extends BaseTool<MyToolParams, MyToolParams> {
// ... method/name/description/parameters as above ...
outputParser = untypedQueryOutputParser;
async normalizeParams(params: MyToolParams) {
return params;
}
async coreAction(params: MyToolParams, _context: Context, client: Client) {
return await someHederaQuery(params, client);
}
async shouldSecondaryAction() {
return false;
}
async secondaryAction(result: any) {
return result;
}
}对于只读工具,重写,使生命周期在之后停止,并让原样传递结果:
shouldSecondaryActioncoreActionsecondaryActiontypescript
export class MyQueryTool extends BaseTool<MyToolParams, MyToolParams> {
// ... method/name/description/parameters as above ...
outputParser = untypedQueryOutputParser;
async normalizeParams(params: MyToolParams) {
return params;
}
async coreAction(params: MyToolParams, _context: Context, client: Client) {
return await someHederaQuery(params, client);
}
async shouldSecondaryAction() {
return false;
}
async secondaryAction(result: any) {
return result;
}
}Creating the Plugin Index
创建插件入口文件
typescript
import { Context, Plugin } from '@hashgraph/hedera-agent-kit';
import myTool, { MY_TOOL_NAME } from './tools/category/my-tool';
export const myPlugin: Plugin = {
name: 'my-hedera-plugin',
version: '1.0.0',
description: 'A plugin for custom Hedera operations',
tools: (context: Context) => {
return [
myTool(context),
];
},
};
export const myPluginToolNames = {
MY_TOOL_NAME,
} as const;
export default { myPlugin, myPluginToolNames };typescript
import { Context, Plugin } from '@hashgraph/hedera-agent-kit';
import myTool, { MY_TOOL_NAME } from './tools/category/my-tool';
export const myPlugin: Plugin = {
name: 'my-hedera-plugin',
version: '1.0.0',
description: 'A plugin for custom Hedera operations',
tools: (context: Context) => {
return [
myTool(context),
];
},
};
export const myPluginToolNames = {
MY_TOOL_NAME,
} as const;
export default { myPlugin, myPluginToolNames };Post-Processing Results
结果后处理
secondaryActionhandleTransactionpostProcesstypescript
const postProcess = (response: RawTransactionResponse) => {
if (response.scheduleId) {
return `Scheduled transaction created.
Transaction ID: ${response.transactionId}
Schedule ID: ${response.scheduleId.toString()}`;
}
return `Operation completed.
Transaction ID: ${response.transactionId}`;
};secondaryActionhandleTransactionpostProcesstypescript
const postProcess = (response: RawTransactionResponse) => {
if (response.scheduleId) {
return `Scheduled transaction created.
Transaction ID: ${response.transactionId}
Schedule ID: ${response.scheduleId.toString()}`;
}
return `Operation completed.
Transaction ID: ${response.transactionId}`;
};RETURN_BYTES
mode — raw.bytes
is a Uint8Array
RETURN_BYTESraw.bytesUint8ArrayRETURN_BYTES
模式——raw.bytes
为Uint8Array
类型
RETURN_BYTESraw.bytesUint8ArrayWhen a tool runs in mode, returned by is always a plain in both Node.js and browser environments. Pass it directly to — no manual conversion is needed.
RETURN_BYTESraw.bytesResponseParserServiceUint8ArrayTransaction.fromBytes()typescript
const bytes = toolCall.parsedData.raw.bytes;
const tx = Transaction.fromBytes(bytes);当工具以模式运行时,返回的在Node.js和浏览器环境中都是普通的类型。直接将其传递给即可——无需手动转换。
RETURN_BYTESResponseParserServiceraw.bytesUint8ArrayTransaction.fromBytes()typescript
const bytes = toolCall.parsedData.raw.bytes;
const tx = Transaction.fromBytes(bytes);Naming Conventions
命名规范
| Element | Convention | Example |
|---|---|---|
| Plugin name | kebab-case | |
| Plugin variable | camelCase | |
| Tool class | PascalCase + | |
| Tool constant | UPPER_SNAKE_CASE + | |
| Tool method value | snake_case + | |
| Tool file | kebab-case | |
| Tool names export | camelCase + | |
| 元素 | 规范 | 示例 |
|---|---|---|
| 插件名称 | 短横线命名(kebab-case) | |
| 插件变量 | 小驼峰命名(camelCase) | |
| 工具类 | 帕斯卡命名(PascalCase)+ | |
| 工具常量 | 大写下划线(UPPER_SNAKE_CASE)+ | |
| 工具method值 | 小写下划线(snake_case)+ | |
| 工具文件 | 短横线命名(kebab-case) | |
| 工具名称导出对象 | 小驼峰(camelCase)+ | |
Common Imports
常用导入
typescript
// From @hashgraph/hedera-agent-kit (core)
import {
Context,
Plugin,
BaseTool,
handleTransaction,
RawTransactionResponse,
transactionToolOutputParser,
untypedQueryOutputParser,
} from '@hashgraph/hedera-agent-kit';
// Built-in plugins live in the /plugins subpath
import { coreTokenPlugin, coreAccountPlugin } from '@hashgraph/hedera-agent-kit/plugins';
// Hedera SDK is a peer dependency
import { Client, Status } from '@hiero-ledger/sdk';
// For parameter validation
import { z } from 'zod';typescript
// From @hashgraph/hedera-agent-kit (core)
import {
Context,
Plugin,
BaseTool,
handleTransaction,
RawTransactionResponse,
transactionToolOutputParser,
untypedQueryOutputParser,
} from '@hashgraph/hedera-agent-kit';
// Built-in plugins live in the /plugins subpath
import { coreTokenPlugin, coreAccountPlugin } from '@hashgraph/hedera-agent-kit/plugins';
// Hedera SDK is a peer dependency
import { Client, Status } from '@hiero-ledger/sdk';
// For parameter validation
import { z } from 'zod';Additional Resources
更多资源
Reference Files
参考文件
For detailed patterns and techniques, consult:
- - Plugin interface,
references/plugin-interface.mdlifecycle in depthBaseTool - - Common Zod schemas for Hedera parameters
references/zod-schema-patterns.md - - Prompt generation patterns for tool descriptions
references/prompt-patterns.md - - Error handling and output parsing patterns
references/error-handling.md
有关详细的模式和技巧,请查阅:
- - 插件接口、
references/plugin-interface.md生命周期详解BaseTool - - Hedera参数常用Zod模式
references/zod-schema-patterns.md - - 工具描述的提示生成模式
references/prompt-patterns.md - - 错误处理与输出解析模式
references/error-handling.md
Example Files
示例文件
Working examples in :
examples/- - Minimal
examples/simple-plugin/query (starter template)BaseTool - - Mutation (
examples/token-plugin/) and query (CreateTokenTool)GetTokenInfoToolsubclassesBaseTool
examples/- - 最简
examples/simple-plugin/查询工具(入门模板)BaseTool - - 变更工具(
examples/token-plugin/)和查询工具(CreateTokenTool)的GetTokenInfoTool子类实现BaseTool
Best Practices
最佳实践
- One file per tool, named after the tool in kebab-case
- Group related tools under category directories in
tools/ - Stable class names: (e.g.,
<DoesWhat>Tool)CreateTokenTool - Resolve defaults in , not in
normalizeParams— keeps the build step purecoreAction - Build, don't submit, in — submission belongs in
coreActionwhere hooks can reactsecondaryAction - Override so logs are tagged with the tool method
handleError - Validate with Zod's — every field; descriptions guide the agent
.describe() - Export tool name constants so consumers can reference tools programmatically
- 每个工具一个文件,以短横线命名的工具名作为文件名
- 将相关工具分组放在目录下的分类子目录中
tools/ - 稳定的类名:格式(例如
<功能>Tool)CreateTokenTool - 在中解析默认值,而不是在
normalizeParams中——保持构建步骤的纯粹性coreAction - 只构建,不提交——提交操作属于
coreAction的职责,这样钩子可以响应secondaryAction - 重写,以便日志带有工具method的标记
handleError - 使用Zod的进行校验——每个字段都要有描述;描述会指导Agent的行为
.describe() - 导出工具名称常量,以便使用者可以以编程方式引用工具
Registering a Plugin with a Toolkit
在工具包中注册插件
Plugins are passed explicitly to the toolkit you choose. Toolkits live in dedicated packages — pick the one that matches your framework:
| Framework | Toolkit package |
|---|---|
| LangChain | |
| Vercel AI SDK | |
| ElizaOS | |
| MCP | |
Emptyarray means zero tools. List every plugin you need explicitly, or usepluginsfrom theallCorePluginssubpath to load every built-in core plugin at once./plugins
typescript
import { Client, PrivateKey } from '@hiero-ledger/sdk';
import { AgentMode } from '@hashgraph/hedera-agent-kit';
import { coreTokenPlugin, coreAccountPlugin } from '@hashgraph/hedera-agent-kit/plugins';
import { HederaLangchainToolkit } from '@hashgraph/hedera-agent-kit-langchain';
import { myPlugin } from './my-hedera-plugin';
const client = Client.forTestnet().setOperator(
process.env.ACCOUNT_ID!,
PrivateKey.fromStringECDSA(process.env.PRIVATE_KEY!),
);
const toolkit = new HederaLangchainToolkit({
client,
configuration: {
plugins: [coreTokenPlugin, coreAccountPlugin, myPlugin],
context: { mode: AgentMode.AUTONOMOUS },
},
});
const tools = toolkit.getTools();To load every built-in core plugin at once, import :
allCorePluginstypescript
import { allCorePlugins } from '@hashgraph/hedera-agent-kit/plugins';
// ...
plugins: [...allCorePlugins, myPlugin],插件需要显式传递给你选择的工具包。工具包位于独立的包中——选择与你的框架匹配的版本:
| 框架 | 工具包包名 |
|---|---|
| LangChain | |
| Vercel AI SDK | |
| ElizaOS | |
| MCP | |
数组为空意味着没有任何工具。 请显式列出你需要的所有插件,或者使用plugins子路径中的/plugins一次性加载所有内置核心插件。allCorePlugins
typescript
import { Client, PrivateKey } from '@hiero-ledger/sdk';
import { AgentMode } from '@hashgraph/hedera-agent-kit';
import { coreTokenPlugin, coreAccountPlugin } from '@hashgraph/hedera-agent-kit/plugins';
import { HederaLangchainToolkit } from '@hashgraph/hedera-agent-kit-langchain';
import { myPlugin } from './my-hedera-plugin';
const client = Client.forTestnet().setOperator(
process.env.ACCOUNT_ID!,
PrivateKey.fromStringECDSA(process.env.PRIVATE_KEY!),
);
const toolkit = new HederaLangchainToolkit({
client,
configuration: {
plugins: [coreTokenPlugin, coreAccountPlugin, myPlugin],
context: { mode: AgentMode.AUTONOMOUS },
},
});
const tools = toolkit.getTools();要一次性加载所有内置核心插件,请导入:
allCorePluginstypescript
import { allCorePlugins } from '@hashgraph/hedera-agent-kit/plugins';
// ...
plugins: [...allCorePlugins, myPlugin],Workflow Summary
工作流程总结
- Create plugin directory with and
index.tssubdirectorytools/ - For each tool, write a subclass and a factory function in its own file
BaseTool - Export tools from along with tool name constants
index.ts - Pass the plugin in the toolkit's array
configuration.plugins - Tools become available to the AI agent
For complete working examples, see the directory.
examples/- 创建插件目录,包含和
index.ts子目录tools/ - 为每个工具编写一个子类,并在单独的文件中编写工厂函数
BaseTool - 在中导出工具以及工具名称常量
index.ts - 将插件添加到工具包的数组中
configuration.plugins - 工具即可供AI Agent使用
完整的可运行示例请参考目录。
examples/