Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: character file plugins import error #2025

Closed
wants to merge 13 commits into from
63 changes: 57 additions & 6 deletions agent/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -174,16 +175,66 @@ 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);
return importedPlugin.default;
try {
// Dynamically import the plugin
const importedPlugin = await import(plugin);

// Check if there's a default export
if (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)) {
possiblePlugins.push(value);
}
}

return possiblePlugins.length > 0
? possiblePlugins
: null;
} catch (error) {
elizaLogger.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);
}

loadedCharacters.push(character);
Expand Down Expand Up @@ -306,9 +357,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);
}
}

Expand Down
32 changes: 20 additions & 12 deletions packages/core/src/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
}

/**
Expand Down
Loading