Files

1 line
1.1 MiB
Plaintext

{"repo": "augchan42/eliza", "files": {"agent/src/index.ts": {"c4b1b47db4a245f812188e7f760aa349a10e9ac5": {"t": 1785745576.5104048, "n": 40207, "h": "a4f6612606ec252f", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { SupabaseDatabaseAdapter } from \"@elizaos/adapter-supabase\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { PrimusAdapter } from \"@elizaos/plugin-primus\";\n\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\nimport { hyperliquidPlugin } from \"@elizaos/plugin-hyperliquid\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport { quaiPlugin } from \"@elizaos/plugin-quai\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\nimport {dominosPlugin} from \"@elizaos/plugin-dominos\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\nfunction mergeCharacters(base: Character, child: Character): Character {\n const mergeObjects = (baseObj: any, childObj: any) => {\n const result: any = {};\n const keys = new Set([...Object.keys(baseObj || {}), ...Object.keys(childObj || {})]);\n keys.forEach(key => {\n if (typeof baseObj[key] === 'object' && typeof childObj[key] === 'object' && !Array.isArray(baseObj[key]) && !Array.isArray(childObj[key])) {\n result[key] = mergeObjects(baseObj[key], childObj[key]);\n } else if (Array.isArray(baseObj[key]) || Array.isArray(childObj[key])) {\n result[key] = [...(baseObj[key] || []), ...(childObj[key] || [])];\n } else {\n result[key] = childObj[key] !== undefined ? childObj[key] : baseObj[key];\n }\n });\n return result;\n };\n return mergeObjects(base, child);\n}\nasync function loadCharacter(filePath: string): Promise<Character> {\n const content = tryLoadFile(filePath);\n if (!content) {\n throw new Error(`Character file not found: ${filePath}`);\n }\n let character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n if (character.extends) {\n elizaLogger.info(`Merging ${character.name} character with parent characters`);\n for (const extendPath of character.extends) {\n const baseCharacter = await loadCharacter(path.resolve(path.dirname(filePath), extendPath));\n character = mergeCharacters(baseCharacter, character);\n elizaLogger.info(`Merged ${character.name} with ${baseCharacter.name}`);\n }\n }\n return character;\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character: Character = await loadCharacter(resolvedPath);\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.MISTRAL:\n return (\n character.settings?.secrets?.MISTRAL_API_KEY ||\n settings.MISTRAL_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n case ModelProviderName.DEEPSEEK:\n return (\n character.settings?.secrets?.DEEPSEEK_API_KEY ||\n settings.DEEPSEEK_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.SUPABASE_URL && process.env.SUPABASE_ANON_KEY) {\n elizaLogger.info(\"Initializing Supabase connection...\");\n const db = new SupabaseDatabaseAdapter(\n process.env.SUPABASE_URL,\n process.env.SUPABASE_ANON_KEY\n );\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\"Successfully connected to Supabase database\");\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to Supabase:\", error);\n });\n\n return db;\n } else if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\"Successfully connected to PostgreSQL database\");\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath = process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n elizaLogger.info(`Initializing SQLite database at ${filePath}...`);\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\"Successfully connected to SQLite database\");\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to SQLite:\", error);\n });\n\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n if (\n process.env.PRIMUS_APP_ID &&\n process.env.PRIMUS_APP_SECRET &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"){\n verifiableInferenceAdapter = new PrimusAdapter({\n appId: process.env.PRIMUS_APP_ID,\n appSecret: process.env.PRIMUS_APP_SECRET,\n attMode: \"proxytls\",\n modelProvider: character.modelProvider,\n token,\n });\n elizaLogger.log(\"Verifiable inference primus adapter initialized\");\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"HYPERLIQUID_PRIVATE_KEY\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"HYPERLIQUID_TESTNET\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n getSecret(character, \"QUAI_PRIVATE_KEY\")\n ? quaiPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "edfba8d0ae46cde21c39e1ac55319bba241ad0cf": {"t": 1785754390.433732, "n": 40207, "h": "a4f6612606ec252f", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { SupabaseDatabaseAdapter } from \"@elizaos/adapter-supabase\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { PrimusAdapter } from \"@elizaos/plugin-primus\";\n\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\nimport { hyperliquidPlugin } from \"@elizaos/plugin-hyperliquid\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport { quaiPlugin } from \"@elizaos/plugin-quai\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\nimport {dominosPlugin} from \"@elizaos/plugin-dominos\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\nfunction mergeCharacters(base: Character, child: Character): Character {\n const mergeObjects = (baseObj: any, childObj: any) => {\n const result: any = {};\n const keys = new Set([...Object.keys(baseObj || {}), ...Object.keys(childObj || {})]);\n keys.forEach(key => {\n if (typeof baseObj[key] === 'object' && typeof childObj[key] === 'object' && !Array.isArray(baseObj[key]) && !Array.isArray(childObj[key])) {\n result[key] = mergeObjects(baseObj[key], childObj[key]);\n } else if (Array.isArray(baseObj[key]) || Array.isArray(childObj[key])) {\n result[key] = [...(baseObj[key] || []), ...(childObj[key] || [])];\n } else {\n result[key] = childObj[key] !== undefined ? childObj[key] : baseObj[key];\n }\n });\n return result;\n };\n return mergeObjects(base, child);\n}\nasync function loadCharacter(filePath: string): Promise<Character> {\n const content = tryLoadFile(filePath);\n if (!content) {\n throw new Error(`Character file not found: ${filePath}`);\n }\n let character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n if (character.extends) {\n elizaLogger.info(`Merging ${character.name} character with parent characters`);\n for (const extendPath of character.extends) {\n const baseCharacter = await loadCharacter(path.resolve(path.dirname(filePath), extendPath));\n character = mergeCharacters(baseCharacter, character);\n elizaLogger.info(`Merged ${character.name} with ${baseCharacter.name}`);\n }\n }\n return character;\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character: Character = await loadCharacter(resolvedPath);\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.MISTRAL:\n return (\n character.settings?.secrets?.MISTRAL_API_KEY ||\n settings.MISTRAL_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n case ModelProviderName.DEEPSEEK:\n return (\n character.settings?.secrets?.DEEPSEEK_API_KEY ||\n settings.DEEPSEEK_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.SUPABASE_URL && process.env.SUPABASE_ANON_KEY) {\n elizaLogger.info(\"Initializing Supabase connection...\");\n const db = new SupabaseDatabaseAdapter(\n process.env.SUPABASE_URL,\n process.env.SUPABASE_ANON_KEY\n );\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\"Successfully connected to Supabase database\");\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to Supabase:\", error);\n });\n\n return db;\n } else if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\"Successfully connected to PostgreSQL database\");\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath = process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n elizaLogger.info(`Initializing SQLite database at ${filePath}...`);\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\"Successfully connected to SQLite database\");\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to SQLite:\", error);\n });\n\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n if (\n process.env.PRIMUS_APP_ID &&\n process.env.PRIMUS_APP_SECRET &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"){\n verifiableInferenceAdapter = new PrimusAdapter({\n appId: process.env.PRIMUS_APP_ID,\n appSecret: process.env.PRIMUS_APP_SECRET,\n attMode: \"proxytls\",\n modelProvider: character.modelProvider,\n token,\n });\n elizaLogger.log(\"Verifiable inference primus adapter initialized\");\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"HYPERLIQUID_PRIVATE_KEY\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"HYPERLIQUID_TESTNET\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n getSecret(character, \"QUAI_PRIVATE_KEY\")\n ? quaiPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "6a9cbe3fce921c8e7d3f9aa529b636cc82bc29a6": {"t": 1785754391.9210253, "n": 40023, "h": "f47f3e00ffa0ddf0", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { SupabaseDatabaseAdapter } from \"@elizaos/adapter-supabase\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { PrimusAdapter } from \"@elizaos/plugin-primus\";\n\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\nimport { hyperliquidPlugin } from \"@elizaos/plugin-hyperliquid\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport { quaiPlugin } from \"@elizaos/plugin-quai\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\nimport {dominosPlugin} from \"@elizaos/plugin-dominos\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\nfunction mergeCharacters(base: Character, child: Character): Character {\n const mergeObjects = (baseObj: any, childObj: any) => {\n const result: any = {};\n const keys = new Set([...Object.keys(baseObj || {}), ...Object.keys(childObj || {})]);\n keys.forEach(key => {\n if (typeof baseObj[key] === 'object' && typeof childObj[key] === 'object' && !Array.isArray(baseObj[key]) && !Array.isArray(childObj[key])) {\n result[key] = mergeObjects(baseObj[key], childObj[key]);\n } else if (Array.isArray(baseObj[key]) || Array.isArray(childObj[key])) {\n result[key] = [...(baseObj[key] || []), ...(childObj[key] || [])];\n } else {\n result[key] = childObj[key] !== undefined ? childObj[key] : baseObj[key];\n }\n });\n return result;\n };\n return mergeObjects(base, child);\n}\nasync function loadCharacter(filePath: string): Promise<Character> {\n const content = tryLoadFile(filePath);\n if (!content) {\n throw new Error(`Character file not found: ${filePath}`);\n }\n let character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n if (character.extends) {\n elizaLogger.info(`Merging ${character.name} character with parent characters`);\n for (const extendPath of character.extends) {\n const baseCharacter = await loadCharacter(path.resolve(path.dirname(filePath), extendPath));\n character = mergeCharacters(baseCharacter, character);\n elizaLogger.info(`Merged ${character.name} with ${baseCharacter.name}`);\n }\n }\n return character;\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character: Character = await loadCharacter(resolvedPath);\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.MISTRAL:\n return (\n character.settings?.secrets?.MISTRAL_API_KEY ||\n settings.MISTRAL_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.SUPABASE_URL && process.env.SUPABASE_ANON_KEY) {\n elizaLogger.info(\"Initializing Supabase connection...\");\n const db = new SupabaseDatabaseAdapter(\n process.env.SUPABASE_URL,\n process.env.SUPABASE_ANON_KEY\n );\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\"Successfully connected to Supabase database\");\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to Supabase:\", error);\n });\n\n return db;\n } else if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\"Successfully connected to PostgreSQL database\");\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath = process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n elizaLogger.info(`Initializing SQLite database at ${filePath}...`);\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\"Successfully connected to SQLite database\");\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to SQLite:\", error);\n });\n\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n if (\n process.env.PRIMUS_APP_ID &&\n process.env.PRIMUS_APP_SECRET &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"){\n verifiableInferenceAdapter = new PrimusAdapter({\n appId: process.env.PRIMUS_APP_ID,\n appSecret: process.env.PRIMUS_APP_SECRET,\n attMode: \"proxytls\",\n modelProvider: character.modelProvider,\n token,\n });\n elizaLogger.log(\"Verifiable inference primus adapter initialized\");\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"HYPERLIQUID_PRIVATE_KEY\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"HYPERLIQUID_TESTNET\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n getSecret(character, \"QUAI_PRIVATE_KEY\")\n ? quaiPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "8d831faae740168f2dec3e8191d387cc828f962f": {"t": 1785754393.3165424, "n": 39056, "h": "408ffd1b366eddf0", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { PrimusAdapter } from \"@elizaos/plugin-primus\";\n\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\nimport { hyperliquidPlugin } from \"@elizaos/plugin-hyperliquid\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport { quaiPlugin } from \"@elizaos/plugin-quai\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\nimport {dominosPlugin} from \"@elizaos/plugin-dominos\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\nfunction mergeCharacters(base: Character, child: Character): Character {\n const mergeObjects = (baseObj: any, childObj: any) => {\n const result: any = {};\n const keys = new Set([...Object.keys(baseObj || {}), ...Object.keys(childObj || {})]);\n keys.forEach(key => {\n if (typeof baseObj[key] === 'object' && typeof childObj[key] === 'object' && !Array.isArray(baseObj[key]) && !Array.isArray(childObj[key])) {\n result[key] = mergeObjects(baseObj[key], childObj[key]);\n } else if (Array.isArray(baseObj[key]) || Array.isArray(childObj[key])) {\n result[key] = [...(baseObj[key] || []), ...(childObj[key] || [])];\n } else {\n result[key] = childObj[key] !== undefined ? childObj[key] : baseObj[key];\n }\n });\n return result;\n };\n return mergeObjects(base, child);\n}\nasync function loadCharacter(filePath: string): Promise<Character> {\n const content = tryLoadFile(filePath);\n if (!content) {\n throw new Error(`Character file not found: ${filePath}`);\n }\n let character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n if (character.extends) {\n elizaLogger.info(`Merging ${character.name} character with parent characters`);\n for (const extendPath of character.extends) {\n const baseCharacter = await loadCharacter(path.resolve(path.dirname(filePath), extendPath));\n character = mergeCharacters(baseCharacter, character);\n elizaLogger.info(`Merged ${character.name} with ${baseCharacter.name}`);\n }\n }\n return character;\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character: Character = await loadCharacter(resolvedPath);\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.MISTRAL:\n return (\n character.settings?.secrets?.MISTRAL_API_KEY ||\n settings.MISTRAL_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n if (\n process.env.PRIMUS_APP_ID &&\n process.env.PRIMUS_APP_SECRET &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"){\n verifiableInferenceAdapter = new PrimusAdapter({\n appId: process.env.PRIMUS_APP_ID,\n appSecret: process.env.PRIMUS_APP_SECRET,\n attMode: \"proxytls\",\n modelProvider: character.modelProvider,\n token,\n });\n elizaLogger.log(\"Verifiable inference primus adapter initialized\");\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"HYPERLIQUID_PRIVATE_KEY\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"HYPERLIQUID_TESTNET\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n getSecret(character, \"QUAI_PRIVATE_KEY\")\n ? quaiPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "1c1072a1980d092a10e82db7c6c14aed5ac1f867": {"t": 1785754394.8107743, "n": 38628, "h": "d0d98dc35bc45e21", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { SupabaseDatabaseAdapter } from \"@elizaos/adapter-supabase\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { PrimusAdapter } from \"@elizaos/plugin-primus\";\n\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\nimport { hyperliquidPlugin } from \"@elizaos/plugin-hyperliquid\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport { quaiPlugin } from \"@elizaos/plugin-quai\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\nimport {dominosPlugin} from \"@elizaos/plugin-dominos\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.MISTRAL:\n return (\n character.settings?.secrets?.MISTRAL_API_KEY ||\n settings.MISTRAL_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.SUPABASE_URL && process.env.SUPABASE_ANON_KEY) {\n elizaLogger.info(\"Initializing Supabase connection...\");\n const db = new SupabaseDatabaseAdapter(\n process.env.SUPABASE_URL,\n process.env.SUPABASE_ANON_KEY\n );\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\"Successfully connected to Supabase database\");\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to Supabase:\", error);\n });\n\n return db;\n } else if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\"Successfully connected to PostgreSQL database\");\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath = process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n elizaLogger.info(`Initializing SQLite database at ${filePath}...`);\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\"Successfully connected to SQLite database\");\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to SQLite:\", error);\n });\n\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n if (\n process.env.PRIMUS_APP_ID &&\n process.env.PRIMUS_APP_SECRET &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"){\n verifiableInferenceAdapter = new PrimusAdapter({\n appId: process.env.PRIMUS_APP_ID,\n appSecret: process.env.PRIMUS_APP_SECRET,\n attMode: \"proxytls\",\n modelProvider: character.modelProvider,\n token,\n });\n elizaLogger.log(\"Verifiable inference primus adapter initialized\");\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"HYPERLIQUID_PRIVATE_KEY\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"HYPERLIQUID_TESTNET\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n getSecret(character, \"QUAI_PRIVATE_KEY\")\n ? quaiPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "4ef4b6a48a18445b21bdd68aa15786a171a57afa": {"t": 1785754396.204191, "n": 38385, "h": "73f58e87d84fe4e1", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\nimport { hyperliquidPlugin } from \"@elizaos/plugin-hyperliquid\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport { quaiPlugin } from \"@elizaos/plugin-quai\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\nfunction mergeCharacters(base: Character, child: Character): Character {\n const mergeObjects = (baseObj: any, childObj: any) => {\n const result: any = {};\n const keys = new Set([...Object.keys(baseObj || {}), ...Object.keys(childObj || {})]);\n keys.forEach(key => {\n if (typeof baseObj[key] === 'object' && typeof childObj[key] === 'object' && !Array.isArray(baseObj[key]) && !Array.isArray(childObj[key])) {\n result[key] = mergeObjects(baseObj[key], childObj[key]);\n } else if (Array.isArray(baseObj[key]) || Array.isArray(childObj[key])) {\n result[key] = [...(baseObj[key] || []), ...(childObj[key] || [])];\n } else {\n result[key] = childObj[key] !== undefined ? childObj[key] : baseObj[key];\n }\n });\n return result;\n };\n return mergeObjects(base, child);\n}\nasync function loadCharacter(filePath: string): Promise<Character> {\n const content = tryLoadFile(filePath);\n if (!content) {\n throw new Error(`Character file not found: ${filePath}`);\n }\n let character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n if (character.extends) {\n elizaLogger.info(`Merging ${character.name} character with parent characters`);\n for (const extendPath of character.extends) {\n const baseCharacter = await loadCharacter(path.resolve(path.dirname(filePath), extendPath));\n character = mergeCharacters(baseCharacter, character);\n elizaLogger.info(`Merged ${character.name} with ${baseCharacter.name}`);\n }\n }\n return character;\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character: Character = await loadCharacter(resolvedPath);\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.MISTRAL:\n return (\n character.settings?.secrets?.MISTRAL_API_KEY ||\n settings.MISTRAL_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"HYPERLIQUID_PRIVATE_KEY\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"HYPERLIQUID_TESTNET\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n getSecret(character, \"QUAI_PRIVATE_KEY\")\n ? quaiPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "9bf45e052fcbbe28cde8db64da2309c47c51bb92": {"t": 1785754397.71298, "n": 37661, "h": "300f6965db497d39", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { PrimusAdapter } from \"@elizaos/plugin-primus\";\n\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\nimport { hyperliquidPlugin } from \"@elizaos/plugin-hyperliquid\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport { quaiPlugin } from \"@elizaos/plugin-quai\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\nimport {dominosPlugin} from \"@elizaos/plugin-dominos\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.MISTRAL:\n return (\n character.settings?.secrets?.MISTRAL_API_KEY ||\n settings.MISTRAL_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n if (\n process.env.PRIMUS_APP_ID &&\n process.env.PRIMUS_APP_SECRET &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"){\n verifiableInferenceAdapter = new PrimusAdapter({\n appId: process.env.PRIMUS_APP_ID,\n appSecret: process.env.PRIMUS_APP_SECRET,\n attMode: \"proxytls\",\n modelProvider: character.modelProvider,\n token,\n });\n elizaLogger.log(\"Verifiable inference primus adapter initialized\");\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"HYPERLIQUID_PRIVATE_KEY\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"HYPERLIQUID_TESTNET\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n getSecret(character, \"QUAI_PRIVATE_KEY\")\n ? quaiPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "560edc6a9a421426a2d35e0f43c88f99c9957399": {"t": 1785754399.2601984, "n": 36990, "h": "461616ad911d2310", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\nimport { hyperliquidPlugin } from \"@elizaos/plugin-hyperliquid\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport { quaiPlugin } from \"@elizaos/plugin-quai\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.MISTRAL:\n return (\n character.settings?.secrets?.MISTRAL_API_KEY ||\n settings.MISTRAL_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"HYPERLIQUID_PRIVATE_KEY\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"HYPERLIQUID_TESTNET\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n getSecret(character, \"QUAI_PRIVATE_KEY\")\n ? quaiPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "3a3a9f21162e6093100f1b57d29bf3ac0b1793bb": {"t": 1785754400.8008542, "n": 37767, "h": "aea4dc62c94a83ae", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { PrimusAdapter } from \"@elizaos/plugin-primus\";\n\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\nimport { hyperliquidPlugin } from \"@elizaos/plugin-hyperliquid\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport { quaiPlugin } from \"@elizaos/plugin-quai\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\nimport {dominosPlugin} from \"@elizaos/plugin-dominos\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.MISTRAL:\n return (\n character.settings?.secrets?.MISTRAL_API_KEY ||\n settings.MISTRAL_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n if (\n process.env.PRIMUS_APP_ID &&\n process.env.PRIMUS_APP_SECRET &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"){\n verifiableInferenceAdapter = new PrimusAdapter({\n appId: process.env.PRIMUS_APP_ID,\n appSecret: process.env.PRIMUS_APP_SECRET,\n attMode: \"proxytls\",\n modelProvider: character.modelProvider,\n token,\n });\n elizaLogger.log(\"Verifiable inference primus adapter initialized\");\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"HYPERLIQUID_PRIVATE_KEY\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"HYPERLIQUID_TESTNET\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n getSecret(character, \"QUAI_PRIVATE_KEY\")\n ? quaiPlugin\n : null,\n getSecret(character, \"QUAI_PRIVATE_KEY\")\n ? quaiPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "f1aeec644d66391aa63f9bfb7e31936805d119f7": {"t": 1785754402.418309, "n": 37096, "h": "a0417e7abe82e68c", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\nimport { hyperliquidPlugin } from \"@elizaos/plugin-hyperliquid\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport { quaiPlugin } from \"@elizaos/plugin-quai\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.MISTRAL:\n return (\n character.settings?.secrets?.MISTRAL_API_KEY ||\n settings.MISTRAL_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"HYPERLIQUID_PRIVATE_KEY\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"HYPERLIQUID_TESTNET\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n getSecret(character, \"QUAI_PRIVATE_KEY\")\n ? quaiPlugin\n : null,\n getSecret(character, \"QUAI_PRIVATE_KEY\")\n ? quaiPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "eedf27840d98478a33882fb047f194c37f4fd2a0": {"t": 1785754403.8909502, "n": 36833, "h": "7a97ddc4971ae24b", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\nimport { hyperliquidPlugin } from \"@elizaos/plugin-hyperliquid\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.MISTRAL:\n return (\n character.settings?.secrets?.MISTRAL_API_KEY ||\n settings.MISTRAL_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"HYPERLIQUID_PRIVATE_KEY\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"HYPERLIQUID_TESTNET\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "4c8fcd53a852508a991dc193d60ea92e9087c8c0": {"t": 1785754405.375167, "n": 36652, "h": "29155feeee2370ea", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\nimport { hyperliquidPlugin } from \"@elizaos/plugin-hyperliquid\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"HYPERLIQUID_PRIVATE_KEY\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"HYPERLIQUID_TESTNET\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "478be4317b237383057666b8aeabce288835524c": {"t": 1785754430.2490633, "n": 36713, "h": "21bebd756492efea", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\nimport { hyperliquidPlugin } from \"@elizaos/plugin-hyperliquid\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"HYPERLIQUID_PRIVATE_KEY\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"HYPERLIQUID_TESTNET\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "0ae4d394de2be0b467fe6efa71da302e2b1f1406": {"t": 1785754431.6403062, "n": 35438, "h": "3d9826e6db15c2f5", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\nimport { hyperliquidPlugin } from \"@elizaos/plugin-hyperliquid\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nfunction isAllStrings(arr: unknown[]): boolean {\n return Array.isArray(arr) && arr.every((item) => typeof item === \"string\");\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n if (isAllStrings(character.plugins)) {\n elizaLogger.info(\"Plugins are: \", character.plugins);\n const importedPlugins = await Promise.all(\n character.plugins.map(async (plugin) => {\n const importedPlugin = await import(plugin);\n return importedPlugin.default;\n })\n );\n character.plugins = importedPlugins;\n }\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"HYPERLIQUID_PRIVATE_KEY\")\n ? hyperliquidPlugin\n : null,\n getSecret(character, \"HYPERLIQUID_TESTNET\")\n ? hyperliquidPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character: Character) => {\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "a50c24f40a58d08efd5679e2ddcc4f0825775aef": {"t": 1785754434.2239916, "n": 36602, "h": "5b62b4e42b4f3a4e", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\n\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.MISTRAL:\n return (\n character.settings?.secrets?.MISTRAL_API_KEY ||\n settings.MISTRAL_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "46e26ab6f874dafd277a49a77f15a3bd5cf1dda1": {"t": 1785754437.0820856, "n": 35165, "h": "ec5d277d1821a91b", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\n\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nfunction isAllStrings(arr: unknown[]): boolean {\n return Array.isArray(arr) && arr.every((item) => typeof item === \"string\");\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n if (isAllStrings(character.plugins)) {\n elizaLogger.info(\"Plugins are: \", character.plugins);\n const importedPlugins = await Promise.all(\n character.plugins.map(async (plugin) => {\n const importedPlugin = await import(plugin);\n return importedPlugin.default;\n })\n );\n character.plugins = importedPlugins;\n }\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.MISTRAL:\n return (\n character.settings?.secrets?.MISTRAL_API_KEY ||\n settings.MISTRAL_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ? coingeckoPlugin : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character: Character) => {\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "d4c9e8126e7376af8d8d3ece882d351b03153641": {"t": 1785754438.644928, "n": 36421, "h": "de3ead810035ad68", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\n\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "45e27afb6d643230b35819e4259c35f8d79fec5a": {"t": 1785754440.6057253, "n": 36197, "h": "3b804bce298b66c8", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\n\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "94e5f261bae40b0a11db883fd6a8497174df4313": {"t": 1785754442.1456776, "n": 36195, "h": "37699af993c128b1", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\n\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "e1b7c805fd51e6f00d532707937c42c49a449d33": {"t": 1785754443.791192, "n": 35971, "h": "e1ffd0af266922a3", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { autonomePlugin } from \"@elizaos/plugin-autonome\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\n\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n getSecret(character, \"AUTONOME_JWT_TOKEN\") ? autonomePlugin : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "b79579db85d53099a3d516023a8b9917e5f103d5": {"t": 1785754445.411829, "n": 35832, "h": "042338ce65fc1b0b", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\n\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "1813bf1962af6d1014c23df4032cf9cdc9db8992": {"t": 1785754449.0048337, "n": 29268, "h": "043eaae0935cb5ff", "c": "import { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\nimport {\n AgentRuntime,\n CacheManager,\n Character,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n CacheStore,\n Client,\n ICacheManager,\n parseBooleanFromText,\n} from \"@elizaos/core\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\nimport { echoChamberPlugin } from \"@elizaos/plugin-echochambers\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\nimport net from \"net\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n character.plugins = await handlePluginImporting(\n character.plugins\n );\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nasync function handlePluginImporting(plugins: string[]) {\n if (plugins.length > 0) {\n elizaLogger.info(\"Plugins are: \", plugins);\n const importedPlugins = await Promise.all(\n plugins.map(async (plugin) => {\n try {\n const importedPlugin = await import(plugin);\n const functionName =\n plugin\n .replace(\"@elizaos/plugin-\", \"\")\n .replace(/-./g, (x) => x[1].toUpperCase()) +\n \"Plugin\"; // Assumes plugin function is camelCased with Plugin suffix\n return (\n importedPlugin.default || importedPlugin[functionName]\n );\n } catch (importError) {\n elizaLogger.error(\n `Failed to import plugin: ${plugin}`,\n importError\n );\n return []; // Return null for failed imports\n }\n })\n );\n return importedPlugins;\n } else {\n return [];\n }\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.XAI_API_KEY ||\n settings.XAI_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n if (clientTypes.includes(Clients.DIRECT)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.success(\n elizaLogger.successesTitle,\n \"Creating runtime for character\",\n character.name\n );\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt\n ? [teePlugin, solanaPlugin]\n : []),\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChamberPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character) => {\n // Handle plugins\n character.plugins = await handlePluginImporting(character.plugins);\n\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "f5f3430bf789a4c6578096bf171e7f93a8889b8b": {"t": 1785754450.4819846, "n": 35356, "h": "174ed0b81b5bb73d", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\n\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nfunction isAllStrings(arr: unknown[]): boolean {\n return Array.isArray(arr) && arr.every((item) => typeof item === \"string\");\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n if (isAllStrings(character.plugins)) {\n elizaLogger.info(\"Plugins are: \", character.plugins);\n const importedPlugins = await Promise.all(\n character.plugins.map(async (plugin) => {\n const importedPlugin = await import(plugin);\n return importedPlugin.default;\n })\n );\n character.plugins = importedPlugins;\n }\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character: Character) => {\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "6ec59efda454290131cb112729df7787eeae7102": {"t": 1785754452.4460135, "n": 35130, "h": "12eee8959bf415dd", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\n\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nfunction isAllStrings(arr: unknown[]): boolean {\n return Array.isArray(arr) && arr.every((item) => typeof item === \"string\");\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n if (isAllStrings(character.plugins)) {\n elizaLogger.info(\"Plugins are: \", character.plugins);\n const importedPlugins = await Promise.all(\n character.plugins.map(async (plugin) => {\n const importedPlugin = await import(plugin);\n return importedPlugin.default;\n })\n );\n character.plugins = importedPlugins;\n }\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character: Character) => {\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "b6ee241012dd9c8b969bd47a720caf485f9f58d2": {"t": 1785754453.9835901, "n": 35249, "h": "1747e9396380cd87", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coinPricePlugin } from \"@elizaos/plugin-coinprice\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\n\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nfunction isAllStrings(arr: unknown[]): boolean {\n return Array.isArray(arr) && arr.every((item) => typeof item === \"string\");\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n if (isAllStrings(character.plugins)) {\n elizaLogger.info(\"Plugins are: \", character.plugins);\n const importedPlugins = await Promise.all(\n character.plugins.map(async (plugin) => {\n const importedPlugin = await import(plugin);\n return importedPlugin.default;\n })\n );\n character.plugins = importedPlugins;\n }\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n coinPricePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n (getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\")))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ? coingeckoPlugin : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character: Character) => {\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "76b9331cec0439b51338d230fc02c5eb1394c141": {"t": 1785754455.571031, "n": 28792, "h": "db3f5d958442fd2e", "c": "import { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\nimport {\n AgentRuntime,\n CacheManager,\n Character,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n CacheStore,\n Client,\n ICacheManager,\n parseBooleanFromText,\n} from \"@elizaos/core\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\nimport { echoChamberPlugin } from \"@elizaos/plugin-echochambers\";\nimport { akashPlugin } from \"@elizaos/plugin-akash\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\nimport net from \"net\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nfunction isAllStrings(arr: unknown[]): boolean {\n return Array.isArray(arr) && arr.every((item) => typeof item === \"string\");\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n if (isAllStrings(character.plugins)) {\n elizaLogger.info(\"Plugins are: \", character.plugins);\n const importedPlugins = await Promise.all(\n character.plugins.map(async (plugin) => {\n const importedPlugin = await import(plugin);\n return importedPlugin.default;\n })\n );\n character.plugins = importedPlugins;\n }\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.XAI_API_KEY ||\n settings.XAI_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n if (clientTypes.includes(Clients.DIRECT)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.success(\n elizaLogger.successesTitle,\n \"Creating runtime for character\",\n character.name\n );\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt\n ? [teePlugin, solanaPlugin]\n : []),\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChamberPlugin\n : null,\n getSecret(character, \"AKASH_MNEMONIC\") &&\n getSecret(character, \"AKASH_WALLET_ADDRESS\")\n ? akashPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character: Character) => {\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "360709d6f1f30f8d0949f5a20db0496861346dc3": {"t": 1785754457.4338171, "n": 34984, "h": "6e9d1768c6182288", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\n\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nfunction isAllStrings(arr: unknown[]): boolean {\n return Array.isArray(arr) && arr.every((item) => typeof item === \"string\");\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n if (isAllStrings(character.plugins)) {\n elizaLogger.info(\"Plugins are: \", character.plugins);\n const importedPlugins = await Promise.all(\n character.plugins.map(async (plugin) => {\n const importedPlugin = await import(plugin);\n return importedPlugin.default;\n })\n );\n character.plugins = importedPlugins;\n }\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\"))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ? coingeckoPlugin : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character: Character) => {\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "2a53f016b26f11a27b28bef62a051c5d73d6bc0d": {"t": 1785754460.1882427, "n": 35169, "h": "ed5cf8145b211992", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coinPricePlugin } from \"@elizaos/plugin-coinprice\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\n\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nfunction isAllStrings(arr: unknown[]): boolean {\n return Array.isArray(arr) && arr.every((item) => typeof item === \"string\");\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n if (isAllStrings(character.plugins)) {\n elizaLogger.info(\"Plugins are: \", character.plugins);\n const importedPlugins = await Promise.all(\n character.plugins.map(async (plugin) => {\n const importedPlugin = await import(plugin);\n return importedPlugin.default;\n })\n );\n character.plugins = importedPlugins;\n }\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n coinPricePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n (getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\")))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character: Character) => {\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "ec1d679a7d038c2f17a50888e7f9919eff52f9e6": {"t": 1785754463.0158684, "n": 35226, "h": "a8010631131b94a4", "c": "import { PGLiteDatabaseAdapter } from \"@elizaos/adapter-pglite\";\nimport { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\n// import { ReclaimAdapter } from \"@elizaos/plugin-reclaim\";\nimport {\n AgentRuntime,\n CacheManager,\n CacheStore,\n Character,\n Client,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n ICacheManager,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n} from \"@elizaos/core\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\n\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { alloraPlugin } from \"@elizaos/plugin-allora\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport { artheraPlugin } from \"@elizaos/plugin-arthera\";\nimport { availPlugin } from \"@elizaos/plugin-avail\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { binancePlugin } from \"@elizaos/plugin-binance\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { coinmarketcapPlugin } from \"@elizaos/plugin-coinmarketcap\";\nimport { coinPricePlugin } from \"@elizaos/plugin-coinprice\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { createCosmosPlugin } from \"@elizaos/plugin-cosmos\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { echoChambersPlugin } from \"@elizaos/plugin-echochambers\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { genLayerPlugin } from \"@elizaos/plugin-genlayer\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { obsidianPlugin } from \"@elizaos/plugin-obsidian\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { solanaAgentkitPlguin } from \"@elizaos/plugin-solana-agentkit\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { sgxPlugin } from \"@elizaos/plugin-sgx\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { teeLogPlugin } from \"@elizaos/plugin-tee-log\";\nimport { teeMarlinPlugin } from \"@elizaos/plugin-tee-marlin\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\n\nimport { coingeckoPlugin } from \"@elizaos/plugin-coingecko\";\nimport { dominosPlugin } from \"@elizaos/plugin-dominos\";\nimport { giphyPlugin } from \"@elizaos/plugin-giphy\";\nimport { letzAIPlugin } from \"@elizaos/plugin-letzai\";\nimport { thirdwebPlugin } from \"@elizaos/plugin-thirdweb\";\n\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\n\nimport { OpacityAdapter } from \"@elizaos/plugin-opacity\";\nimport { openWeatherPlugin } from \"@elizaos/plugin-open-weather\";\nimport { stargazePlugin } from \"@elizaos/plugin-stargaze\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport net from \"net\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nfunction isAllStrings(arr: unknown[]): boolean {\n return Array.isArray(arr) && arr.every((item) => typeof item === \"string\");\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters: Character[] = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content: string | null = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n if (isAllStrings(character.plugins)) {\n elizaLogger.info(\"Plugins are: \", character.plugins);\n const importedPlugins = await Promise.all(\n character.plugins.map(async (plugin) => {\n const importedPlugin = await import(plugin);\n return importedPlugin.default;\n })\n );\n character.plugins = importedPlugins;\n }\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string | undefined {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.NINETEEN_AI:\n return (\n character.settings?.secrets?.NINETEEN_AI_API_KEY ||\n settings.NINETEEN_AI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n case ModelProviderName.LETZAI:\n return (\n character.settings?.secrets?.LETZAI_API_KEY ||\n settings.LETZAI_API_KEY\n );\n case ModelProviderName.INFERA:\n return (\n character.settings?.secrets?.INFERA_API_KEY ||\n settings.INFERA_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else if (process.env.PGLITE_DATA_DIR) {\n elizaLogger.info(\"Initializing PgLite adapter...\");\n // `dataDir: memory://` for in memory pg\n const db = new PGLiteDatabaseAdapter({\n dataDir: process.env.PGLITE_DATA_DIR,\n });\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n // Start Auto Client if \"auto\" detected as a configured client\n if (clientTypes.includes(Clients.AUTO)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.log(`Creating runtime for character ${character.name}`);\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n // Initialize Reclaim adapter if environment variables are present\n // let verifiableInferenceAdapter;\n // if (\n // process.env.RECLAIM_APP_ID &&\n // process.env.RECLAIM_APP_SECRET &&\n // process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n // ) {\n // verifiableInferenceAdapter = new ReclaimAdapter({\n // appId: process.env.RECLAIM_APP_ID,\n // appSecret: process.env.RECLAIM_APP_SECRET,\n // modelProvider: character.modelProvider,\n // token,\n // });\n // elizaLogger.log(\"Verifiable inference adapter initialized\");\n // }\n // Initialize Opacity adapter if environment variables are present\n let verifiableInferenceAdapter;\n if (\n process.env.OPACITY_TEAM_ID &&\n process.env.OPACITY_CLOUDFLARE_NAME &&\n process.env.OPACITY_PROVER_URL &&\n process.env.VERIFIABLE_INFERENCE_ENABLED === \"true\"\n ) {\n verifiableInferenceAdapter = new OpacityAdapter({\n teamId: process.env.OPACITY_TEAM_ID,\n teamName: process.env.OPACITY_CLOUDFLARE_NAME,\n opacityProverUrl: process.env.OPACITY_PROVER_URL,\n modelProvider: character.modelProvider,\n token: token,\n });\n elizaLogger.log(\"Verifiable inference adapter initialized\");\n elizaLogger.log(\"teamId\", process.env.OPACITY_TEAM_ID);\n elizaLogger.log(\"teamName\", process.env.OPACITY_CLOUDFLARE_NAME);\n elizaLogger.log(\"opacityProverUrl\", process.env.OPACITY_PROVER_URL);\n elizaLogger.log(\"modelProvider\", character.modelProvider);\n elizaLogger.log(\"token\", token);\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n coinPricePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n getSecret(character, \"SOLANA_PRIVATE_KEY\")\n ? solanaAgentkitPlguin\n : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n getSecret(character, \"COSMOS_RECOVERY_PHRASE\") &&\n getSecret(character, \"COSMOS_AVAILABLE_CHAINS\") &&\n createCosmosPlugin(),\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINMARKETCAP_API_KEY\")\n ? coinmarketcapPlugin\n : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"NINETEEN_AI_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin] : []),\n getSecret(character, \"SGX\") ? sgxPlugin : null,\n (getSecret(character, \"ENABLE_TEE_LOG\") &&\n ((teeMode !== TEEMode.OFF && walletSecretSalt) ||\n getSecret(character, \"SGX\")))\n ? teeLogPlugin\n : null,\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"COINGECKO_API_KEY\") ||\n getSecret(character, \"COINGECKO_PRO_API_KEY\")\n ? coingeckoPlugin\n : null,\n getSecret(character, \"EVM_PROVIDER_URL\") ? goatPlugin : null,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"BINANCE_API_KEY\") &&\n getSecret(character, \"BINANCE_SECRET_KEY\")\n ? binancePlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TEE_MARLIN\") ? teeMarlinPlugin : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"THIRDWEB_SECRET_KEY\") ? thirdwebPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChambersPlugin\n : null,\n getSecret(character, \"LETZAI_API_KEY\") ? letzAIPlugin : null,\n getSecret(character, \"STARGAZE_ENDPOINT\") ? stargazePlugin : null,\n getSecret(character, \"GIPHY_API_KEY\") ? giphyPlugin : null,\n getSecret(character, \"GENLAYER_PRIVATE_KEY\")\n ? genLayerPlugin\n : null,\n getSecret(character, \"AVAIL_SEED\") &&\n getSecret(character, \"AVAIL_APP_ID\")\n ? availPlugin\n : null,\n getSecret(character, \"OPEN_WEATHER_API_KEY\")\n ? openWeatherPlugin\n : null,\n getSecret(character, \"OBSIDIAN_API_TOKEN\") ? obsidianPlugin : null,\n getSecret(character, \"ARTHERA_PRIVATE_KEY\")?.startsWith(\"0x\")\n ? artheraPlugin\n : null,\n getSecret(character, \"ALLORA_API_KEY\") ? alloraPlugin : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n verifiableInferenceAdapter,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n if (!character?.id) {\n throw new Error(\n \"initializeFsCache requires id to be set in character definition\"\n );\n }\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n if (!character?.id) {\n throw new Error(\n \"CacheStore.REDIS requires id to be set in character definition\"\n );\n }\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n if (!baseDir) {\n throw new Error(\n \"baseDir must be provided for CacheStore.FILESYSTEM.\"\n );\n }\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character: Character) => {\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}, "c6d378b7561625bc962c3fbd5f1ddecb86469373": {"t": 1785754464.5435395, "n": 28790, "h": "b4d410429986051f", "c": "import { PostgresDatabaseAdapter } from \"@elizaos/adapter-postgres\";\nimport { SqliteDatabaseAdapter } from \"@elizaos/adapter-sqlite\";\nimport { AutoClientInterface } from \"@elizaos/client-auto\";\nimport { DiscordClientInterface } from \"@elizaos/client-discord\";\nimport { FarcasterAgentClient } from \"@elizaos/client-farcaster\";\nimport { LensAgentClient } from \"@elizaos/client-lens\";\nimport { SlackClientInterface } from \"@elizaos/client-slack\";\nimport { TelegramClientInterface } from \"@elizaos/client-telegram\";\nimport { TwitterClientInterface } from \"@elizaos/client-twitter\";\nimport {\n AgentRuntime,\n CacheManager,\n Character,\n Clients,\n DbCacheAdapter,\n defaultCharacter,\n elizaLogger,\n FsCacheAdapter,\n IAgentRuntime,\n IDatabaseAdapter,\n IDatabaseCacheAdapter,\n ModelProviderName,\n settings,\n stringToUuid,\n validateCharacterConfig,\n CacheStore,\n Client,\n ICacheManager,\n parseBooleanFromText,\n} from \"@elizaos/core\";\nimport { RedisClient } from \"@elizaos/adapter-redis\";\nimport { zgPlugin } from \"@elizaos/plugin-0g\";\nimport { bootstrapPlugin } from \"@elizaos/plugin-bootstrap\";\nimport createGoatPlugin from \"@elizaos/plugin-goat\";\n// import { intifacePlugin } from \"@elizaos/plugin-intiface\";\nimport { DirectClient } from \"@elizaos/client-direct\";\nimport { aptosPlugin } from \"@elizaos/plugin-aptos\";\nimport {\n advancedTradePlugin,\n coinbaseCommercePlugin,\n coinbaseMassPaymentsPlugin,\n tokenContractPlugin,\n tradePlugin,\n webhookPlugin,\n} from \"@elizaos/plugin-coinbase\";\nimport { confluxPlugin } from \"@elizaos/plugin-conflux\";\nimport { evmPlugin } from \"@elizaos/plugin-evm\";\nimport { storyPlugin } from \"@elizaos/plugin-story\";\nimport { flowPlugin } from \"@elizaos/plugin-flow\";\nimport { fuelPlugin } from \"@elizaos/plugin-fuel\";\nimport { imageGenerationPlugin } from \"@elizaos/plugin-image-generation\";\nimport { ThreeDGenerationPlugin } from \"@elizaos/plugin-3d-generation\";\nimport { multiversxPlugin } from \"@elizaos/plugin-multiversx\";\nimport { nearPlugin } from \"@elizaos/plugin-near\";\nimport { nftGenerationPlugin } from \"@elizaos/plugin-nft-generation\";\nimport { createNodePlugin } from \"@elizaos/plugin-node\";\nimport { solanaPlugin } from \"@elizaos/plugin-solana\";\nimport { suiPlugin } from \"@elizaos/plugin-sui\";\nimport { TEEMode, teePlugin } from \"@elizaos/plugin-tee\";\nimport { tonPlugin } from \"@elizaos/plugin-ton\";\nimport { lensPlugin } from \"@elizaos/plugin-lensNetwork\";\nimport { zksyncEraPlugin } from \"@elizaos/plugin-zksync-era\";\nimport { cronosZkEVMPlugin } from \"@elizaos/plugin-cronoszkevm\";\nimport { abstractPlugin } from \"@elizaos/plugin-abstract\";\nimport { avalanchePlugin } from \"@elizaos/plugin-avalanche\";\nimport { webSearchPlugin } from \"@elizaos/plugin-web-search\";\nimport { echoChamberPlugin } from \"@elizaos/plugin-echochambers\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport yargs from \"yargs\";\nimport net from \"net\";\n\nconst __filename = fileURLToPath(import.meta.url); // get the resolved path to the file\nconst __dirname = path.dirname(__filename); // get the name of the directory\n\nexport const wait = (minTime: number = 1000, maxTime: number = 3000) => {\n const waitTime =\n Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;\n return new Promise((resolve) => setTimeout(resolve, waitTime));\n};\n\nconst logFetch = async (url: string, options: any) => {\n elizaLogger.debug(`Fetching ${url}`);\n // Disabled to avoid disclosure of sensitive information such as API keys\n // elizaLogger.debug(JSON.stringify(options, null, 2));\n return fetch(url, options);\n};\n\nexport function parseArguments(): {\n character?: string;\n characters?: string;\n} {\n try {\n return yargs(process.argv.slice(3))\n .option(\"character\", {\n type: \"string\",\n description: \"Path to the character JSON file\",\n })\n .option(\"characters\", {\n type: \"string\",\n description:\n \"Comma separated list of paths to character JSON files\",\n })\n .parseSync();\n } catch (error) {\n elizaLogger.error(\"Error parsing arguments:\", error);\n return {};\n }\n}\n\nfunction tryLoadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch (e) {\n return null;\n }\n}\n\nfunction isAllStrings(arr: unknown[]): boolean {\n return Array.isArray(arr) && arr.every((item) => typeof item === \"string\");\n}\n\nexport async function loadCharacters(\n charactersArg: string\n): Promise<Character[]> {\n let characterPaths = charactersArg\n ?.split(\",\")\n .map((filePath) => filePath.trim());\n const loadedCharacters = [];\n\n if (characterPaths?.length > 0) {\n for (const characterPath of characterPaths) {\n let content = null;\n let resolvedPath = \"\";\n\n // Try different path resolutions in order\n const pathsToTry = [\n characterPath, // exact path as specified\n path.resolve(process.cwd(), characterPath), // relative to cwd\n path.resolve(process.cwd(), \"agent\", characterPath), // Add this\n path.resolve(__dirname, characterPath), // relative to current script\n path.resolve(\n __dirname,\n \"characters\",\n path.basename(characterPath)\n ), // relative to agent/characters\n path.resolve(\n __dirname,\n \"../characters\",\n path.basename(characterPath)\n ), // relative to characters dir from agent\n path.resolve(\n __dirname,\n \"../../characters\",\n path.basename(characterPath)\n ), // relative to project root characters dir\n ];\n\n elizaLogger.info(\n \"Trying paths:\",\n pathsToTry.map((p) => ({\n path: p,\n exists: fs.existsSync(p),\n }))\n );\n\n for (const tryPath of pathsToTry) {\n content = tryLoadFile(tryPath);\n if (content !== null) {\n resolvedPath = tryPath;\n break;\n }\n }\n\n if (content === null) {\n elizaLogger.error(\n `Error loading character from ${characterPath}: File not found in any of the expected locations`\n );\n elizaLogger.error(\"Tried the following paths:\");\n pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));\n process.exit(1);\n }\n\n try {\n const character = JSON.parse(content);\n validateCharacterConfig(character);\n\n // .id isn't really valid\n const characterId = character.id || character.name;\n const characterPrefix = `CHARACTER.${characterId.toUpperCase().replace(/ /g, \"_\")}.`;\n\n const characterSettings = Object.entries(process.env)\n .filter(([key]) => key.startsWith(characterPrefix))\n .reduce((settings, [key, value]) => {\n const settingKey = key.slice(characterPrefix.length);\n return { ...settings, [settingKey]: value };\n }, {});\n\n if (Object.keys(characterSettings).length > 0) {\n character.settings = character.settings || {};\n character.settings.secrets = {\n ...characterSettings,\n ...character.settings.secrets,\n };\n }\n\n // Handle plugins\n if (isAllStrings(character.plugins)) {\n elizaLogger.info(\"Plugins are: \", character.plugins);\n const importedPlugins = await Promise.all(\n character.plugins.map(async (plugin) => {\n const importedPlugin = await import(plugin);\n return importedPlugin.default;\n })\n );\n character.plugins = importedPlugins;\n }\n\n loadedCharacters.push(character);\n elizaLogger.info(\n `Successfully loaded character from: ${resolvedPath}`\n );\n } catch (e) {\n elizaLogger.error(\n `Error parsing character from ${resolvedPath}: ${e}`\n );\n process.exit(1);\n }\n }\n }\n\n if (loadedCharacters.length === 0) {\n elizaLogger.info(\"No characters found, using default character\");\n loadedCharacters.push(defaultCharacter);\n }\n\n return loadedCharacters;\n}\n\nexport function getTokenForProvider(\n provider: ModelProviderName,\n character: Character\n): string {\n switch (provider) {\n // no key needed for llama_local or gaianet\n case ModelProviderName.LLAMALOCAL:\n return \"\";\n case ModelProviderName.OLLAMA:\n return \"\";\n case ModelProviderName.GAIANET:\n return \"\";\n case ModelProviderName.OPENAI:\n return (\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.ETERNALAI:\n return (\n character.settings?.secrets?.ETERNALAI_API_KEY ||\n settings.ETERNALAI_API_KEY\n );\n case ModelProviderName.LLAMACLOUD:\n case ModelProviderName.TOGETHER:\n return (\n character.settings?.secrets?.LLAMACLOUD_API_KEY ||\n settings.LLAMACLOUD_API_KEY ||\n character.settings?.secrets?.TOGETHER_API_KEY ||\n settings.TOGETHER_API_KEY ||\n character.settings?.secrets?.XAI_API_KEY ||\n settings.XAI_API_KEY ||\n character.settings?.secrets?.OPENAI_API_KEY ||\n settings.OPENAI_API_KEY\n );\n case ModelProviderName.CLAUDE_VERTEX:\n case ModelProviderName.ANTHROPIC:\n return (\n character.settings?.secrets?.ANTHROPIC_API_KEY ||\n character.settings?.secrets?.CLAUDE_API_KEY ||\n settings.ANTHROPIC_API_KEY ||\n settings.CLAUDE_API_KEY\n );\n case ModelProviderName.REDPILL:\n return (\n character.settings?.secrets?.REDPILL_API_KEY ||\n settings.REDPILL_API_KEY\n );\n case ModelProviderName.OPENROUTER:\n return (\n character.settings?.secrets?.OPENROUTER ||\n settings.OPENROUTER_API_KEY\n );\n case ModelProviderName.GROK:\n return (\n character.settings?.secrets?.GROK_API_KEY ||\n settings.GROK_API_KEY\n );\n case ModelProviderName.HEURIST:\n return (\n character.settings?.secrets?.HEURIST_API_KEY ||\n settings.HEURIST_API_KEY\n );\n case ModelProviderName.GROQ:\n return (\n character.settings?.secrets?.GROQ_API_KEY ||\n settings.GROQ_API_KEY\n );\n case ModelProviderName.GALADRIEL:\n return (\n character.settings?.secrets?.GALADRIEL_API_KEY ||\n settings.GALADRIEL_API_KEY\n );\n case ModelProviderName.FAL:\n return (\n character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY\n );\n case ModelProviderName.ALI_BAILIAN:\n return (\n character.settings?.secrets?.ALI_BAILIAN_API_KEY ||\n settings.ALI_BAILIAN_API_KEY\n );\n case ModelProviderName.VOLENGINE:\n return (\n character.settings?.secrets?.VOLENGINE_API_KEY ||\n settings.VOLENGINE_API_KEY\n );\n case ModelProviderName.NANOGPT:\n return (\n character.settings?.secrets?.NANOGPT_API_KEY ||\n settings.NANOGPT_API_KEY\n );\n case ModelProviderName.HYPERBOLIC:\n return (\n character.settings?.secrets?.HYPERBOLIC_API_KEY ||\n settings.HYPERBOLIC_API_KEY\n );\n case ModelProviderName.VENICE:\n return (\n character.settings?.secrets?.VENICE_API_KEY ||\n settings.VENICE_API_KEY\n );\n case ModelProviderName.AKASH_CHAT_API:\n return (\n character.settings?.secrets?.AKASH_CHAT_API_KEY ||\n settings.AKASH_CHAT_API_KEY\n );\n case ModelProviderName.GOOGLE:\n return (\n character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||\n settings.GOOGLE_GENERATIVE_AI_API_KEY\n );\n default:\n const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;\n elizaLogger.error(errorMessage);\n throw new Error(errorMessage);\n }\n}\n\nfunction initializeDatabase(dataDir: string) {\n if (process.env.POSTGRES_URL) {\n elizaLogger.info(\"Initializing PostgreSQL connection...\");\n const db = new PostgresDatabaseAdapter({\n connectionString: process.env.POSTGRES_URL,\n parseInputs: true,\n });\n\n // Test the connection\n db.init()\n .then(() => {\n elizaLogger.success(\n \"Successfully connected to PostgreSQL database\"\n );\n })\n .catch((error) => {\n elizaLogger.error(\"Failed to connect to PostgreSQL:\", error);\n });\n\n return db;\n } else {\n const filePath =\n process.env.SQLITE_FILE ?? path.resolve(dataDir, \"db.sqlite\");\n // \":memory:\";\n const db = new SqliteDatabaseAdapter(new Database(filePath));\n return db;\n }\n}\n\n// also adds plugins from character file into the runtime\nexport async function initializeClients(\n character: Character,\n runtime: IAgentRuntime\n) {\n // each client can only register once\n // and if we want two we can explicitly support it\n const clients: Record<string, any> = {};\n const clientTypes: string[] =\n character.clients?.map((str) => str.toLowerCase()) || [];\n elizaLogger.log(\"initializeClients\", clientTypes, \"for\", character.name);\n\n if (clientTypes.includes(Clients.DIRECT)) {\n const autoClient = await AutoClientInterface.start(runtime);\n if (autoClient) clients.auto = autoClient;\n }\n\n if (clientTypes.includes(Clients.DISCORD)) {\n const discordClient = await DiscordClientInterface.start(runtime);\n if (discordClient) clients.discord = discordClient;\n }\n\n if (clientTypes.includes(Clients.TELEGRAM)) {\n const telegramClient = await TelegramClientInterface.start(runtime);\n if (telegramClient) clients.telegram = telegramClient;\n }\n\n if (clientTypes.includes(Clients.TWITTER)) {\n const twitterClient = await TwitterClientInterface.start(runtime);\n if (twitterClient) {\n clients.twitter = twitterClient;\n }\n }\n\n if (clientTypes.includes(Clients.FARCASTER)) {\n // why is this one different :(\n const farcasterClient = new FarcasterAgentClient(runtime);\n if (farcasterClient) {\n farcasterClient.start();\n clients.farcaster = farcasterClient;\n }\n }\n if (clientTypes.includes(\"lens\")) {\n const lensClient = new LensAgentClient(runtime);\n lensClient.start();\n clients.lens = lensClient;\n }\n\n elizaLogger.log(\"client keys\", Object.keys(clients));\n\n // TODO: Add Slack client to the list\n // Initialize clients as an object\n\n if (clientTypes.includes(\"slack\")) {\n const slackClient = await SlackClientInterface.start(runtime);\n if (slackClient) clients.slack = slackClient; // Use object property instead of push\n }\n\n function determineClientType(client: Client): string {\n // Check if client has a direct type identifier\n if (\"type\" in client) {\n return (client as any).type;\n }\n\n // Check constructor name\n const constructorName = client.constructor?.name;\n if (constructorName && !constructorName.includes(\"Object\")) {\n return constructorName.toLowerCase().replace(\"client\", \"\");\n }\n\n // Fallback: Generate a unique identifier\n return `client_${Date.now()}`;\n }\n\n if (character.plugins?.length > 0) {\n for (const plugin of character.plugins) {\n if (plugin.clients) {\n for (const client of plugin.clients) {\n const startedClient = await client.start(runtime);\n const clientType = determineClientType(client);\n elizaLogger.debug(\n `Initializing client of type: ${clientType}`\n );\n clients[clientType] = startedClient;\n }\n }\n }\n }\n\n return clients;\n}\n\nfunction getSecret(character: Character, secret: string) {\n return character.settings?.secrets?.[secret] || process.env[secret];\n}\n\nlet nodePlugin: any | undefined;\n\nexport async function createAgent(\n character: Character,\n db: IDatabaseAdapter,\n cache: ICacheManager,\n token: string\n): Promise<AgentRuntime> {\n elizaLogger.success(\n elizaLogger.successesTitle,\n \"Creating runtime for character\",\n character.name\n );\n\n nodePlugin ??= createNodePlugin();\n\n const teeMode = getSecret(character, \"TEE_MODE\") || \"OFF\";\n const walletSecretSalt = getSecret(character, \"WALLET_SECRET_SALT\");\n\n // Validate TEE configuration\n if (teeMode !== TEEMode.OFF && !walletSecretSalt) {\n elizaLogger.error(\n \"WALLET_SECRET_SALT required when TEE_MODE is enabled\"\n );\n throw new Error(\"Invalid TEE configuration\");\n }\n\n let goatPlugin: any | undefined;\n\n if (getSecret(character, \"EVM_PRIVATE_KEY\")) {\n goatPlugin = await createGoatPlugin((secret) =>\n getSecret(character, secret)\n );\n }\n\n return new AgentRuntime({\n databaseAdapter: db,\n token,\n modelProvider: character.modelProvider,\n evaluators: [],\n character,\n // character.plugins are handled when clients are added\n plugins: [\n bootstrapPlugin,\n getSecret(character, \"CONFLUX_CORE_PRIVATE_KEY\")\n ? confluxPlugin\n : null,\n nodePlugin,\n getSecret(character, \"TAVILY_API_KEY\") ? webSearchPlugin : null,\n getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? solanaPlugin\n : null,\n (getSecret(character, \"NEAR_ADDRESS\") ||\n getSecret(character, \"NEAR_WALLET_PUBLIC_KEY\")) &&\n getSecret(character, \"NEAR_WALLET_SECRET_KEY\")\n ? nearPlugin\n : null,\n getSecret(character, \"EVM_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\"0x\"))\n ? evmPlugin\n : null,\n (getSecret(character, \"SOLANA_PUBLIC_KEY\") ||\n (getSecret(character, \"WALLET_PUBLIC_KEY\") &&\n !getSecret(character, \"WALLET_PUBLIC_KEY\")?.startsWith(\n \"0x\"\n ))) &&\n getSecret(character, \"SOLANA_ADMIN_PUBLIC_KEY\") &&\n getSecret(character, \"SOLANA_PRIVATE_KEY\") &&\n getSecret(character, \"SOLANA_ADMIN_PRIVATE_KEY\")\n ? nftGenerationPlugin\n : null,\n getSecret(character, \"ZEROG_PRIVATE_KEY\") ? zgPlugin : null,\n getSecret(character, \"COINBASE_COMMERCE_KEY\")\n ? coinbaseCommercePlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ||\n getSecret(character, \"OPENAI_API_KEY\") ||\n getSecret(character, \"VENICE_API_KEY\") ||\n getSecret(character, \"HEURIST_API_KEY\") ||\n getSecret(character, \"LIVEPEER_GATEWAY_URL\")\n ? imageGenerationPlugin\n : null,\n getSecret(character, \"FAL_API_KEY\") ? ThreeDGenerationPlugin : null,\n ...(getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\")\n ? [\n coinbaseMassPaymentsPlugin,\n tradePlugin,\n tokenContractPlugin,\n advancedTradePlugin,\n ]\n : []),\n ...(teeMode !== TEEMode.OFF && walletSecretSalt\n ? [teePlugin, solanaPlugin]\n : []),\n getSecret(character, \"COINBASE_API_KEY\") &&\n getSecret(character, \"COINBASE_PRIVATE_KEY\") &&\n getSecret(character, \"COINBASE_NOTIFICATION_URI\")\n ? webhookPlugin\n : null,\n goatPlugin,\n getSecret(character, \"ABSTRACT_PRIVATE_KEY\")\n ? abstractPlugin\n : null,\n getSecret(character, \"FLOW_ADDRESS\") &&\n getSecret(character, \"FLOW_PRIVATE_KEY\")\n ? flowPlugin\n : null,\n getSecret(character, \"LENS_ADDRESS\") &&\n getSecret(character, \"LENS_PRIVATE_KEY\")\n ? lensPlugin\n : null,\n getSecret(character, \"APTOS_PRIVATE_KEY\") ? aptosPlugin : null,\n getSecret(character, \"MVX_PRIVATE_KEY\") ? multiversxPlugin : null,\n getSecret(character, \"ZKSYNC_PRIVATE_KEY\") ? zksyncEraPlugin : null,\n getSecret(character, \"CRONOSZKEVM_PRIVATE_KEY\")\n ? cronosZkEVMPlugin\n : null,\n getSecret(character, \"TON_PRIVATE_KEY\") ? tonPlugin : null,\n getSecret(character, \"SUI_PRIVATE_KEY\") ? suiPlugin : null,\n getSecret(character, \"STORY_PRIVATE_KEY\") ? storyPlugin : null,\n getSecret(character, \"FUEL_PRIVATE_KEY\") ? fuelPlugin : null,\n getSecret(character, \"AVALANCHE_PRIVATE_KEY\")\n ? avalanchePlugin\n : null,\n getSecret(character, \"ECHOCHAMBERS_API_URL\") &&\n getSecret(character, \"ECHOCHAMBERS_API_KEY\")\n ? echoChamberPlugin\n : null,\n ].filter(Boolean),\n providers: [],\n actions: [],\n services: [],\n managers: [],\n cacheManager: cache,\n fetch: logFetch,\n });\n}\n\nfunction initializeFsCache(baseDir: string, character: Character) {\n const cacheDir = path.resolve(baseDir, character.id, \"cache\");\n\n const cache = new CacheManager(new FsCacheAdapter(cacheDir));\n return cache;\n}\n\nfunction initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {\n const cache = new CacheManager(new DbCacheAdapter(db, character.id));\n return cache;\n}\n\nfunction initializeCache(\n cacheStore: string,\n character: Character,\n baseDir?: string,\n db?: IDatabaseCacheAdapter\n) {\n switch (cacheStore) {\n case CacheStore.REDIS:\n if (process.env.REDIS_URL) {\n elizaLogger.info(\"Connecting to Redis...\");\n const redisClient = new RedisClient(process.env.REDIS_URL);\n return new CacheManager(\n new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter\n );\n } else {\n throw new Error(\"REDIS_URL environment variable is not set.\");\n }\n\n case CacheStore.DATABASE:\n if (db) {\n elizaLogger.info(\"Using Database Cache...\");\n return initializeDbCache(character, db);\n } else {\n throw new Error(\n \"Database adapter is not provided for CacheStore.Database.\"\n );\n }\n\n case CacheStore.FILESYSTEM:\n elizaLogger.info(\"Using File System Cache...\");\n return initializeFsCache(baseDir, character);\n\n default:\n throw new Error(\n `Invalid cache store: ${cacheStore} or required configuration missing.`\n );\n }\n}\n\nasync function startAgent(\n character: Character,\n directClient: DirectClient\n): Promise<AgentRuntime> {\n let db: IDatabaseAdapter & IDatabaseCacheAdapter;\n try {\n character.id ??= stringToUuid(character.name);\n character.username ??= character.name;\n\n const token = getTokenForProvider(character.modelProvider, character);\n const dataDir = path.join(__dirname, \"../data\");\n\n if (!fs.existsSync(dataDir)) {\n fs.mkdirSync(dataDir, { recursive: true });\n }\n\n db = initializeDatabase(dataDir) as IDatabaseAdapter &\n IDatabaseCacheAdapter;\n\n await db.init();\n\n const cache = initializeCache(\n process.env.CACHE_STORE ?? CacheStore.DATABASE,\n character,\n \"\",\n db\n ); // \"\" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env\n const runtime: AgentRuntime = await createAgent(\n character,\n db,\n cache,\n token\n );\n\n // start services/plugins/process knowledge\n await runtime.initialize();\n\n // start assigned clients\n runtime.clients = await initializeClients(character, runtime);\n\n // add to container\n directClient.registerAgent(runtime);\n\n // report to console\n elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);\n\n return runtime;\n } catch (error) {\n elizaLogger.error(\n `Error starting agent for character ${character.name}:`,\n error\n );\n elizaLogger.error(error);\n if (db) {\n await db.close();\n }\n throw error;\n }\n}\n\nconst checkPortAvailable = (port: number): Promise<boolean> => {\n return new Promise((resolve) => {\n const server = net.createServer();\n\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n }\n });\n\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port);\n });\n};\n\nconst startAgents = async () => {\n const directClient = new DirectClient();\n let serverPort = parseInt(settings.SERVER_PORT || \"3000\");\n const args = parseArguments();\n let charactersArg = args.characters || args.character;\n let characters = [defaultCharacter];\n\n if (charactersArg) {\n characters = await loadCharacters(charactersArg);\n }\n\n try {\n for (const character of characters) {\n await startAgent(character, directClient);\n }\n } catch (error) {\n elizaLogger.error(\"Error starting agents:\", error);\n }\n\n // Find available port\n while (!(await checkPortAvailable(serverPort))) {\n elizaLogger.warn(\n `Port ${serverPort} is in use, trying ${serverPort + 1}`\n );\n serverPort++;\n }\n\n // upload some agent functionality into directClient\n directClient.startAgent = async (character: Character) => {\n // wrap it so we don't have to inject directClient later\n return startAgent(character, directClient);\n };\n\n directClient.start(serverPort);\n\n if (serverPort !== parseInt(settings.SERVER_PORT || \"3000\")) {\n elizaLogger.log(`Server started on alternate port ${serverPort}`);\n }\n\n elizaLogger.log(\n \"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents. When running multiple agents, use client with different port `SERVER_PORT=3001 pnpm start:client`\"\n );\n};\n\nstartAgents().catch((error) => {\n elizaLogger.error(\"Unhandled error in startAgents:\", error);\n process.exit(1);\n});\n"}}}}