@hashgraphonline/standards-agent-kit
Version:
A modular SDK for building on-chain autonomous agents using Hashgraph Online Standards, including HCS-10 for agent discovery and communication.
122 lines (106 loc) • 3.83 kB
text/typescript
import { PluginContext } from './PluginInterface';
import * as fs from 'fs';
import * as path from 'path';
import { IPlugin } from './PluginInterface';
/**
* Configuration for loading a plugin
*/
export interface PluginLoadOptions {
/**
* Whether to initialize the plugin after loading
* @default true
*/
initialize?: boolean;
}
/**
* Utility for loading plugins from different sources
*/
export class PluginLoader {
/**
* Load a plugin from a directory
* @param directory Path to the directory containing the plugin
* @param context Context to provide to the plugin during initialization
* @param options Options for loading the plugin
* @returns The loaded plugin instance
*/
static async loadFromDirectory(
directory: string,
context: PluginContext,
options: PluginLoadOptions = { initialize: true }
): Promise<IPlugin> {
const manifestPath = path.join(directory, 'plugin.json');
if (!fs.existsSync(manifestPath)) {
throw new Error(`Plugin manifest not found at ${manifestPath}`);
}
try {
const manifestContent = fs.readFileSync(manifestPath, 'utf8');
const manifest = JSON.parse(manifestContent);
// Validate manifest
if (!manifest.id || !manifest.main) {
throw new Error('Invalid plugin manifest: missing required fields (id, main)');
}
// Load the plugin module
const mainPath = path.join(directory, manifest.main);
if (!fs.existsSync(mainPath)) {
throw new Error(`Plugin main file not found at ${mainPath}`);
}
// Import the plugin module
const pluginModule = await import(mainPath);
const PluginClass = pluginModule.default || pluginModule[manifest.id];
if (!PluginClass) {
throw new Error(`Could not find plugin class in ${mainPath}`);
}
// Create an instance of the plugin
const plugin = new PluginClass();
// Validate that it implements the IPlugin interface
if (!this.isValidPlugin(plugin)) {
throw new Error(`Plugin does not implement the IPlugin interface correctly`);
}
// Initialize the plugin if requested
if (options.initialize) {
await plugin.initialize(context);
}
return plugin;
} catch (error) {
throw new Error(`Failed to load plugin from directory ${directory}: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Load a plugin from an npm package
* @param packageName Name of the npm package containing the plugin
* @param context Context to provide to the plugin during initialization
* @param options Options for loading the plugin
* @returns The loaded plugin instance
*/
static async loadFromPackage(
packageName: string,
context: PluginContext,
options: PluginLoadOptions = { initialize: true }
): Promise<IPlugin> {
try {
// Resolve the package path
const packagePath = require.resolve(packageName);
const packageDir = path.dirname(packagePath);
return this.loadFromDirectory(packageDir, context, options);
} catch (error) {
throw new Error(`Failed to load plugin from package ${packageName}: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Check if an object implements the IPlugin interface
* @param obj Object to check
* @returns true if the object implements IPlugin, false otherwise
*/
private static isValidPlugin(obj: any): obj is IPlugin {
return (
obj &&
typeof obj.id === 'string' &&
typeof obj.name === 'string' &&
typeof obj.description === 'string' &&
typeof obj.version === 'string' &&
typeof obj.author === 'string' &&
typeof obj.initialize === 'function' &&
typeof obj.getTools === 'function'
);
}
}