From 13482b41b4d8fb93abb87dc8e8463127b6cd0226 Mon Sep 17 00:00:00 2001 From: mbcse Date: Wed, 8 Jan 2025 17:56:39 +0530 Subject: [PATCH 1/5] Fix: Plugin import errors as default was undefined --- agent/src/index.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/agent/src/index.ts b/agent/src/index.ts index 78771314bb..e02ea0b4a2 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -180,7 +180,13 @@ export async function loadCharacters( const importedPlugins = await Promise.all( character.plugins.map(async (plugin) => { const importedPlugin = await import(plugin); - return importedPlugin.default; + if (importedPlugin.default) { + return importedPlugin.default; + } else { + return importedPlugin[ + Object.keys(importedPlugin)[0] + ]; + } }) ); character.plugins = importedPlugins; @@ -306,9 +312,9 @@ export function getTokenForProvider( settings.AKASH_CHAT_API_KEY ); default: - const errorMessage = `Failed to get token - unsupported model provider: ${provider}` - elizaLogger.error(errorMessage) - throw new Error(errorMessage) + const errorMessage = `Failed to get token - unsupported model provider: ${provider}`; + elizaLogger.error(errorMessage); + throw new Error(errorMessage); } } From e003ba263c0ff106364c19d276a80697e64646d1 Mon Sep 17 00:00:00 2001 From: mbcse Date: Wed, 8 Jan 2025 20:47:30 +0530 Subject: [PATCH 2/5] fix: multiple plugin exports --- agent/src/index.ts | 74 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/agent/src/index.ts b/agent/src/index.ts index e02ea0b4a2..59bb75d816 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -58,6 +58,7 @@ import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; import yargs from "yargs"; +import { Plugin } from "@ai16z/eliza/src/types"; const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file const __dirname = path.dirname(__filename); // get the name of the directory @@ -174,22 +175,79 @@ export async function loadCharacters( const character = JSON.parse(content); validateCharacterConfig(character); + function isPlugin(value: any): value is Plugin { + return ( + typeof value === "object" && + value !== null && + typeof value.name === "string" && + typeof value.description === "string" && + (value.actions === undefined || + Array.isArray(value.actions)) && + (value.providers === undefined || + Array.isArray(value.providers)) && + (value.evaluators === undefined || + Array.isArray(value.evaluators)) && + (value.services === undefined || + Array.isArray(value.services)) && + (value.clients === undefined || + Array.isArray(value.clients)) + ); + } + // Handle plugins if (isAllStrings(character.plugins)) { elizaLogger.info("Plugins are: ", character.plugins); + const importedPlugins = await Promise.all( character.plugins.map(async (plugin) => { - const importedPlugin = await import(plugin); - if (importedPlugin.default) { - return importedPlugin.default; - } else { - return importedPlugin[ - Object.keys(importedPlugin)[0] - ]; + try { + // Dynamically import the plugin + const importedPlugin = await import(plugin); + console.log( + "Imported plugin: ", + importedPlugin + ); + + // Check if there's a default export + if (importedPlugin.default) { + console.log( + "Default Export Found: ", + importedPlugin.default + ); + return importedPlugin.default; + } + + // Check other exports for potential plugins + const possiblePlugins = []; + for (const [key, value] of Object.entries( + importedPlugin + )) { + // Check if the export matches the plugin type + if (isPlugin(value)) { + console.log( + `Valid Plugin Found in ${plugin}:`, + key + ); + possiblePlugins.push(value); + } + } + + return possiblePlugins.length > 0 + ? possiblePlugins + : null; + } catch (error) { + console.error( + `Failed to import plugin "${plugin}":`, + error + ); + return null; // Return null for failed imports } }) ); - character.plugins = importedPlugins; + + // Flatten and filter out null or empty plugin arrays + character.plugins = importedPlugins.flat().filter(Boolean); + console.log("Character Plugins are: ", character.plugins); } loadedCharacters.push(character); From 1b04c5b0cbef9736445aa934d8430de4b1d8b285 Mon Sep 17 00:00:00 2001 From: mbcse Date: Wed, 8 Jan 2025 21:07:12 +0530 Subject: [PATCH 3/5] Remove Console logs --- agent/src/index.ts | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/agent/src/index.ts b/agent/src/index.ts index 59bb75d816..6b38c8c424 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -203,17 +203,9 @@ export async function loadCharacters( try { // Dynamically import the plugin const importedPlugin = await import(plugin); - console.log( - "Imported plugin: ", - importedPlugin - ); // Check if there's a default export if (importedPlugin.default) { - console.log( - "Default Export Found: ", - importedPlugin.default - ); return importedPlugin.default; } @@ -224,10 +216,6 @@ export async function loadCharacters( )) { // Check if the export matches the plugin type if (isPlugin(value)) { - console.log( - `Valid Plugin Found in ${plugin}:`, - key - ); possiblePlugins.push(value); } } @@ -236,7 +224,7 @@ export async function loadCharacters( ? possiblePlugins : null; } catch (error) { - console.error( + elizaLogger.error( `Failed to import plugin "${plugin}":`, error ); @@ -247,7 +235,6 @@ export async function loadCharacters( // Flatten and filter out null or empty plugin arrays character.plugins = importedPlugins.flat().filter(Boolean); - console.log("Character Plugins are: ", character.plugins); } loadedCharacters.push(character); From fa2ef7cbe50d86014fba45c6693387bc3d02eb0e Mon Sep 17 00:00:00 2001 From: mbcse Date: Thu, 9 Jan 2025 00:43:27 +0530 Subject: [PATCH 4/5] fix: Filter Duplicate imports --- packages/core/src/runtime.ts | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/packages/core/src/runtime.ts b/packages/core/src/runtime.ts index 2ba5f016b4..be1422372c 100644 --- a/packages/core/src/runtime.ts +++ b/packages/core/src/runtime.ts @@ -46,6 +46,7 @@ import { type Memory, } from "./types.ts"; import { stringToUuid } from "./uuid.ts"; +import _ from "lodash"; /** * Represents the runtime environment for an agent, handling message processing, @@ -340,11 +341,13 @@ export class AgentRuntime implements IAgentRuntime { this.token = opts.token; - this.plugins = [ + const allPlugins = [ ...(opts.character?.plugins ?? []), ...(opts.plugins ?? []), ]; + this.plugins = _.uniqBy(allPlugins, "name"); + this.plugins.forEach((plugin) => { plugin.actions?.forEach((action) => { this.registerAction(action); @@ -410,22 +413,27 @@ export class AgentRuntime implements IAgentRuntime { } async stop() { - elizaLogger.debug('runtime::stop - character', this.character) - // stop services, they don't have a stop function + elizaLogger.debug("runtime::stop - character", this.character); + // stop services, they don't have a stop function // just initialize - // plugins + // plugins // have actions, providers, evaluators (no start/stop) // services (just initialized), clients - // client have a start - for(const cStr in this.clients) { - const c = this.clients[cStr] - elizaLogger.log('runtime::stop - requesting', cStr, 'client stop for', this.character.name) - c.stop() - } - // we don't need to unregister with directClient - // don't need to worry about knowledge + // client have a start + for (const cStr in this.clients) { + const c = this.clients[cStr]; + elizaLogger.log( + "runtime::stop - requesting", + cStr, + "client stop for", + this.character.name + ); + c.stop(); + } + // we don't need to unregister with directClient + // don't need to worry about knowledge } /** From d91e1d9ee4d04cccd101427505365528fab311bd Mon Sep 17 00:00:00 2001 From: mbcse Date: Sun, 12 Jan 2025 21:30:34 +0530 Subject: [PATCH 5/5] Fixes and refactor --- agent/src/index.ts | 111 ++++++++++++++++++++++------------- packages/core/src/runtime.ts | 15 +++-- 2 files changed, 79 insertions(+), 47 deletions(-) diff --git a/agent/src/index.ts b/agent/src/index.ts index b475951234..a8da153b5e 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -102,8 +102,8 @@ import net from "net"; import path from "path"; import { fileURLToPath } from "url"; import yargs from "yargs"; -import { Plugin } from "@ai16z/eliza/src/types"; -import {dominosPlugin} from "@elizaos/plugin-dominos"; +import { Plugin } from "@elizaos/core"; +import { dominosPlugin } from "@elizaos/plugin-dominos"; const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file const __dirname = path.dirname(__filename); // get the name of the directory @@ -121,6 +121,10 @@ const logFetch = async (url: string, options: any) => { return fetch(url, options); }; +function isAllStrings(arr: unknown[]): boolean { + return Array.isArray(arr) && arr.every((item) => typeof item === "string"); +} + export function parseArguments(): { character?: string; characters?: string; @@ -153,14 +157,29 @@ function tryLoadFile(filePath: string): string | null { function mergeCharacters(base: Character, child: Character): Character { const mergeObjects = (baseObj: any, childObj: any) => { const result: any = {}; - const keys = new Set([...Object.keys(baseObj || {}), ...Object.keys(childObj || {})]); - keys.forEach(key => { - if (typeof baseObj[key] === 'object' && typeof childObj[key] === 'object' && !Array.isArray(baseObj[key]) && !Array.isArray(childObj[key])) { + const keys = new Set([ + ...Object.keys(baseObj || {}), + ...Object.keys(childObj || {}), + ]); + keys.forEach((key) => { + if ( + typeof baseObj[key] === "object" && + typeof childObj[key] === "object" && + !Array.isArray(baseObj[key]) && + !Array.isArray(childObj[key]) + ) { result[key] = mergeObjects(baseObj[key], childObj[key]); - } else if (Array.isArray(baseObj[key]) || Array.isArray(childObj[key])) { - result[key] = [...(baseObj[key] || []), ...(childObj[key] || [])]; + } else if ( + Array.isArray(baseObj[key]) || + Array.isArray(childObj[key]) + ) { + result[key] = [ + ...(baseObj[key] || []), + ...(childObj[key] || []), + ]; } else { - result[key] = childObj[key] !== undefined ? childObj[key] : baseObj[key]; + result[key] = + childObj[key] !== undefined ? childObj[key] : baseObj[key]; } }); return result; @@ -175,32 +194,36 @@ async function loadCharacter(filePath: string): Promise { let character = JSON.parse(content); validateCharacterConfig(character); - // .id isn't really valid - const characterId = character.id || character.name; - const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, "_")}.`; - const characterSettings = Object.entries(process.env) - .filter(([key]) => key.startsWith(characterPrefix)) - .reduce((settings, [key, value]) => { - const settingKey = key.slice(characterPrefix.length); - return { ...settings, [settingKey]: value }; - }, {}); - if (Object.keys(characterSettings).length > 0) { - character.settings = character.settings || {}; - character.settings.secrets = { - ...characterSettings, - ...character.settings.secrets, - }; - } - // Handle plugins - character.plugins = await handlePluginImporting( - character.plugins - ); + // .id isn't really valid + const characterId = character.id || character.name; + const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, "_")}.`; + const characterSettings = Object.entries(process.env) + .filter(([key]) => key.startsWith(characterPrefix)) + .reduce((settings, [key, value]) => { + const settingKey = key.slice(characterPrefix.length); + return { ...settings, [settingKey]: value }; + }, {}); + if (Object.keys(characterSettings).length > 0) { + character.settings = character.settings || {}; + character.settings.secrets = { + ...characterSettings, + ...character.settings.secrets, + }; + } + // Handle plugins + character.plugins = await handlePluginImporting(character.plugins); if (character.extends) { - elizaLogger.info(`Merging ${character.name} character with parent characters`); + elizaLogger.info( + `Merging ${character.name} character with parent characters` + ); for (const extendPath of character.extends) { - const baseCharacter = await loadCharacter(path.resolve(path.dirname(filePath), extendPath)); + const baseCharacter = await loadCharacter( + path.resolve(path.dirname(filePath), extendPath) + ); character = mergeCharacters(baseCharacter, character); - elizaLogger.info(`Merged ${character.name} with ${baseCharacter.name}`); + elizaLogger.info( + `Merged ${character.name} with ${baseCharacter.name}` + ); } } return character; @@ -289,7 +312,7 @@ export async function loadCharacters( ...character.settings.secrets, }; } - + function isPlugin(value: any): value is Plugin { return ( typeof value === "object" && @@ -307,7 +330,7 @@ export async function loadCharacters( (value.clients === undefined || Array.isArray(value.clients)) ); - } + } // Handle plugins if (isAllStrings(character.plugins)) { @@ -555,7 +578,9 @@ function initializeDatabase(dataDir: string) { // Test the connection db.init() .then(() => { - elizaLogger.success("Successfully connected to Supabase database"); + elizaLogger.success( + "Successfully connected to Supabase database" + ); }) .catch((error) => { elizaLogger.error("Failed to connect to Supabase:", error); @@ -572,7 +597,9 @@ function initializeDatabase(dataDir: string) { // Test the connection db.init() .then(() => { - elizaLogger.success("Successfully connected to PostgreSQL database"); + elizaLogger.success( + "Successfully connected to PostgreSQL database" + ); }) .catch((error) => { elizaLogger.error("Failed to connect to PostgreSQL:", error); @@ -587,14 +614,17 @@ function initializeDatabase(dataDir: string) { }); return db; } else { - const filePath = process.env.SQLITE_FILE ?? path.resolve(dataDir, "db.sqlite"); + const filePath = + process.env.SQLITE_FILE ?? path.resolve(dataDir, "db.sqlite"); elizaLogger.info(`Initializing SQLite database at ${filePath}...`); const db = new SqliteDatabaseAdapter(new Database(filePath)); // Test the connection db.init() .then(() => { - elizaLogger.success("Successfully connected to SQLite database"); + elizaLogger.success( + "Successfully connected to SQLite database" + ); }) .catch((error) => { elizaLogger.error("Failed to connect to SQLite:", error); @@ -772,7 +802,8 @@ export async function createAgent( if ( process.env.PRIMUS_APP_ID && process.env.PRIMUS_APP_SECRET && - process.env.VERIFIABLE_INFERENCE_ENABLED === "true"){ + process.env.VERIFIABLE_INFERENCE_ENABLED === "true" + ) { verifiableInferenceAdapter = new PrimusAdapter({ appId: process.env.PRIMUS_APP_ID, appSecret: process.env.PRIMUS_APP_SECRET, @@ -934,9 +965,7 @@ export async function createAgent( getSecret(character, "AKASH_WALLET_ADDRESS") ? akashPlugin : null, - getSecret(character, "QUAI_PRIVATE_KEY") - ? quaiPlugin - : null, + getSecret(character, "QUAI_PRIVATE_KEY") ? quaiPlugin : null, ].filter(Boolean), providers: [], actions: [], diff --git a/packages/core/src/runtime.ts b/packages/core/src/runtime.ts index 127c3fd41e..adc439362e 100644 --- a/packages/core/src/runtime.ts +++ b/packages/core/src/runtime.ts @@ -53,10 +53,6 @@ import { type Memory, } from "./types.ts"; import { stringToUuid } from "./uuid.ts"; -import _ from "lodash"; -import { readFile } from 'fs/promises'; -import { join } from 'path'; - /** * Represents the runtime environment for an agent, handling message processing, @@ -375,12 +371,19 @@ export class AgentRuntime implements IAgentRuntime { this.token = opts.token; - const allPlugins = [ + const combinedPlugins = [ ...(opts.character?.plugins ?? []), ...(opts.plugins ?? []), ]; - this.plugins = _.uniqBy(allPlugins, "name"); + const seen = new Set(); + this.plugins = combinedPlugins.filter((plugin) => { + if (seen.has(plugin.name)) { + return false; + } + seen.add(plugin.name); + return true; + }); this.plugins.forEach((plugin) => { plugin.actions?.forEach((action) => {