Skip to main content

Creating a Plugin

Plugin Interface

Every plugin must implement the Plugin interface:
export interface Plugin {
  name: string;
  version?: string;
  description?: string;
  tools: (context: Context) => Tool[];
}

Tool Interface

Each tool must implement the Tool interface:
export type Tool = {
  method: string;
  name: string;
  description: string;
  parameters: z.ZodObject<any, any>;
  execute: (client: Client, context: Context, params: any) => Promise<any>;
  // transactionToolOutputParser and untypedQueryOutputParser can be used. If required, define a custom parser
  outputParser?: (rawOutput: string) => { raw: any; humanMessage: string };
};
See typescript/src/shared/tools.ts for the full definition.

Step-by-Step Guide

Step 1: Create Plugin Directory Structure

  my-custom-plugin/
  ├── index.ts                    # Plugin definition and exports
  ├── tools/
  │   └── my-service/
  │       └── my-tool.ts         # Individual tool implementation

Step 2: Implement Your Tool

Create your tool file (e.g., tools/my-service/my-tool.ts):
import { z } from "zod";
import { Context, Tool, handleTransaction } from "hedera-agent-kit";
import { Client, PrivateKey, AccountId } from "@hashgraph/sdk";
import dotenv from "dotenv";

// Load environment variables
dotenv.config();

// Define parameter schema
const myToolParameters = (context: Context = {}) =>
  z.object({
    requiredParam: z.string().describe("Description of required parameter"),
    optionalParam: z
      .string()
      .optional()
      .describe("Description of optional parameter"),
  });

// Create prompt function
const myToolPrompt = (context: Context = {}) => {
  return `
  This tool performs a specific operation.

  Parameters:
  - requiredParam (string, required): Description
  - optionalParam (string, optional): Description
  `;
};

// Implement tool logic
const myToolExecute = async (
  client: Client,
  context: Context,
  params: z.infer<ReturnType<typeof myToolParameters>>,
) => {
  try {
    // Your implementation here
    const result = await someHederaOperation(params);
    return result;
  } catch (error) {
    if (error instanceof Error) {
      return error.message;
    }
    return "Operation failed";
  }
};

export const MY_TOOL = "my_tool";

const tool = (context: Context): Tool => ({
  method: MY_TOOL,
  name: "My Custom Tool",
  description: myToolPrompt(context),
  parameters: myToolParameters(context),
  execute: myToolExecute,
});

export default tool;

Step 3: Create Plugin Definition

Create your plugin index file (index.ts):
  import { Context } from '@/shared';
  import { Plugin } from '@/shared/plugin';
  import myTool, { MY_TOOL } from './tools/my-service/my-tool';

  export const myCustomPlugin: Plugin = {
    name: 'my-custom-plugin',
    version: '1.0.0',
    description: 'A plugin for custom functionality',
    tools: (context: Context) => {
      return [myTool(context)];
    },
  };

  export const myCustomPluginToolNames = {
    MY_TOOL,
  } as const;

  export default { myCustomPlugin, myCustomPluginToolNames };

Best Practices

Parameter Validation
  • Use Zod schemas for robust input validation
  • Provide clear descriptions for all parameters
  • Mark required vs optional parameters appropriately
Tool Organization
  • Group related tools by service type
  • Use consistent naming conventions
  • Follow the established directory structure
Transaction Handling
  • Use handleTransaction() to facilitate human-in-the-loop and autonomous execution flows
  • Respect the AgentMode (AUTONOMOUS vs RETURN_BYTES)
  • Implement proper transaction building patterns

Tool Output Parsing

The Hedera Agent Kit tools return a structured JSON output that needs to be parsed to be useful for the agent and the user. LangChain v0.3 (Classic) In the classic approach, the agent handles the tool output automatically, but you may need to parse it if you are handling tool calls manually. LangChain v1 (New) In LangChain v1, we use the ResponseParserService to handle tool outputs. This service normalizes the output from both transaction and query tools into a consistent format:
{
  raw: any;          // The raw data returned by the tool (e.g., transaction receipt, query result)
  humanMessage: string; // A human-readable message describing the result
}
This allows you to easily display a user-friendly message while still having access to the raw data for further processing.

Using Your Custom Plugin

LangChain v0.3 (Classic)
import { HederaLangchainToolkit } from "hedera-agent-kit";
import {
  myCustomPlugin,
  myCustomPluginToolNames,
} from "./plugins/my-custom-plugin";

const toolkit = new HederaLangchainToolkit({
  client,
  configuration: {
    tools: [myCustomPluginToolNames.MY_TOOL],
    plugins: [myCustomPlugin],
    context: {
      mode: AgentMode.AUTONOMOUS,
    },
  },
});
LangChain v1 (New)
import { HederaLangchainToolkit, ResponseParserService } from "hedera-agent-kit";
import {
  myCustomPlugin,
  myCustomPluginToolNames,
} from "./plugins/my-custom-plugin";

// Initialize toolkit
const toolkit = new HederaLangchainToolkit({
  client,
  configuration: {
    tools: [myCustomPluginToolNames.MY_TOOL],
    plugins: [myCustomPlugin],
    context: {
      mode: AgentMode.AUTONOMOUS,
    },
  },
});

// Initialize response parser
const responseParsingService = new ResponseParserService(toolkit.getTools());

// ... inside your agent loop ...
const response = await agent.invoke({ messages: [/* ... */] });

// Parse tool outputs
const parsedToolData = responseParsingService.parseNewToolMessages(response);
const toolCall = parsedToolData[0]; // assuming only one tool was called

if (toolCall) {
  console.log('Human Message:', toolCall.parsedData.humanMessage);
  console.log('Raw Data:', toolCall.parsedData.raw);
}

Examples and References

Publish and Register Your Plugin

To create a plugin to be use with the Hedera Agent Kit, you will need to create a plugin in your own repository, publish an npm package, and provide a description of the functionality included in that plugin, as well as the required and optional parameters. Once you have a repository, published npm package, and a README with a description of the functionality included in that plugin in your plugin’s repo, as well, add it to the Hedera Agent Kit by forking and opening a Pull Request that includes:
  1. Include the plugin as a bullet point under the Third Party Plugin section in the README.md in the hedera-agent-kit-js.
    • Include the name, a brief description, and a link to the repository with the README, as well the URL linked to the published npm package.
  2. If you would like to include your plugin functionality in the Hedera plugin built for ElizaOS simply make a PR to add your plugin name to the plugins array in the Hedera ElizaOS plugin where the configuration is initiated. The hedera-agent-kit adaptor architecture means your plugin functionality will be usable with no additional configuration needed.
Please also reach out in the Hedera Discord in the Support > developer-help-desk channel or create an Issue in this repository for help building, publishing, and promoting your plugin.

Plugin README Template

## Plugin Name
This plugin was built by <?> for the <project, platform, etc>. It was built to enable <who?> to <do what?>

_Feel free to include a description of your project and how it can be used with the Hedera Agent Kit. 

### Installation

```bash
npm install <plugin-name>
```

### Usage

```javascript
import { myPlugin } from '<plugin-name>';
```

```javascript
 const hederaAgentToolkit = new HederaLangchainToolkit({
    client,
    configuration: {
      context: {
        mode: AgentMode.AUTONOMOUS,
      },
      plugins: [coreTokenPlugin, coreAccountPlugin, coreConsensusPlugin, coreQueriesPlugin, myPlugin],
    },
  });
```

### Functionality
Describe the different tools or individual pieces of functionality included in this plugin, and how to use them.

**Plugin Name**
_High level description of the plugin_

| Tool Name                                       | Description                                        |Usage                                             |
| ----------------------------------------------- | -------------------------------------------------- |--------------------------------------------------------- |
| `YOUR_PLUGIN_TOOL_NAME`| What it does | How to use. Include a list of parameters and their descriptions|

Resources