@elizaos/agent 0.1.7-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +62 -0
- package/src/index.ts +731 -0
- package/tsconfig.json +20 -0
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@elizaos/agent",
|
|
3
|
+
"version": "0.1.7-alpha.1",
|
|
4
|
+
"main": "src/index.ts",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node --loader ts-node/esm src/index.ts",
|
|
8
|
+
"dev": "node --loader ts-node/esm src/index.ts",
|
|
9
|
+
"check-types": "tsc --noEmit"
|
|
10
|
+
},
|
|
11
|
+
"nodemonConfig": {
|
|
12
|
+
"watch": [
|
|
13
|
+
"src",
|
|
14
|
+
"../core/dist"
|
|
15
|
+
],
|
|
16
|
+
"ext": "ts,json",
|
|
17
|
+
"exec": "node --enable-source-maps --loader ts-node/esm src/index.ts"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@elizaos/adapter-postgres": "workspace:*",
|
|
21
|
+
"@elizaos/adapter-redis": "workspace:*",
|
|
22
|
+
"@elizaos/adapter-sqlite": "workspace:*",
|
|
23
|
+
"@elizaos/client-auto": "workspace:*",
|
|
24
|
+
"@elizaos/client-direct": "workspace:*",
|
|
25
|
+
"@elizaos/client-discord": "workspace:*",
|
|
26
|
+
"@elizaos/client-farcaster": "workspace:*",
|
|
27
|
+
"@elizaos/client-lens": "workspace:*",
|
|
28
|
+
"@elizaos/client-telegram": "workspace:*",
|
|
29
|
+
"@elizaos/client-twitter": "workspace:*",
|
|
30
|
+
"@elizaos/client-slack": "workspace:*",
|
|
31
|
+
"@elizaos/core": "workspace:*",
|
|
32
|
+
"@elizaos/plugin-0g": "workspace:*",
|
|
33
|
+
"@elizaos/plugin-aptos": "workspace:*",
|
|
34
|
+
"@elizaos/plugin-bootstrap": "workspace:*",
|
|
35
|
+
"@elizaos/plugin-intiface": "workspace:*",
|
|
36
|
+
"@elizaos/plugin-coinbase": "workspace:*",
|
|
37
|
+
"@elizaos/plugin-conflux": "workspace:*",
|
|
38
|
+
"@elizaos/plugin-evm": "workspace:*",
|
|
39
|
+
"@elizaos/plugin-flow": "workspace:*",
|
|
40
|
+
"@elizaos/plugin-story": "workspace:*",
|
|
41
|
+
"@elizaos/plugin-goat": "workspace:*",
|
|
42
|
+
"@elizaos/plugin-icp": "workspace:*",
|
|
43
|
+
"@elizaos/plugin-image-generation": "workspace:*",
|
|
44
|
+
"@elizaos/plugin-nft-generation": "workspace:*",
|
|
45
|
+
"@elizaos/plugin-node": "workspace:*",
|
|
46
|
+
"@elizaos/plugin-solana": "workspace:*",
|
|
47
|
+
"@elizaos/plugin-starknet": "workspace:*",
|
|
48
|
+
"@elizaos/plugin-ton": "workspace:*",
|
|
49
|
+
"@elizaos/plugin-sui": "workspace:*",
|
|
50
|
+
"@elizaos/plugin-tee": "workspace:*",
|
|
51
|
+
"@elizaos/plugin-multiversx": "workspace:*",
|
|
52
|
+
"@elizaos/plugin-near": "workspace:*",
|
|
53
|
+
"@elizaos/plugin-zksync-era": "workspace:*",
|
|
54
|
+
"readline": "1.3.0",
|
|
55
|
+
"ws": "8.18.0",
|
|
56
|
+
"yargs": "17.7.2"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"ts-node": "10.9.2",
|
|
60
|
+
"tsup": "8.3.5"
|
|
61
|
+
}
|
|
62
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,731 @@
|
|
|
1
|
+
import { PostgresDatabaseAdapter } from "@elizaos/adapter-postgres";
|
|
2
|
+
import { SqliteDatabaseAdapter } from "@elizaos/adapter-sqlite";
|
|
3
|
+
import { AutoClientInterface } from "@elizaos/client-auto";
|
|
4
|
+
import { DiscordClientInterface } from "@elizaos/client-discord";
|
|
5
|
+
import { FarcasterAgentClient } from "@elizaos/client-farcaster";
|
|
6
|
+
import { LensAgentClient } from "@elizaos/client-lens";
|
|
7
|
+
import { SlackClientInterface } from "@elizaos/client-slack";
|
|
8
|
+
import { TelegramClientInterface } from "@elizaos/client-telegram";
|
|
9
|
+
import { TwitterClientInterface } from "@elizaos/client-twitter";
|
|
10
|
+
import {
|
|
11
|
+
AgentRuntime,
|
|
12
|
+
CacheManager,
|
|
13
|
+
Character,
|
|
14
|
+
Clients,
|
|
15
|
+
DbCacheAdapter,
|
|
16
|
+
defaultCharacter,
|
|
17
|
+
elizaLogger,
|
|
18
|
+
FsCacheAdapter,
|
|
19
|
+
IAgentRuntime,
|
|
20
|
+
ICacheManager,
|
|
21
|
+
IDatabaseAdapter,
|
|
22
|
+
IDatabaseCacheAdapter,
|
|
23
|
+
ModelProviderName,
|
|
24
|
+
settings,
|
|
25
|
+
stringToUuid,
|
|
26
|
+
validateCharacterConfig,
|
|
27
|
+
CacheStore,
|
|
28
|
+
} from "@elizaos/core";
|
|
29
|
+
import { RedisClient } from "@elizaos/adapter-redis";
|
|
30
|
+
import { zgPlugin } from "@elizaos/plugin-0g";
|
|
31
|
+
import { bootstrapPlugin } from "@elizaos/plugin-bootstrap";
|
|
32
|
+
import createGoatPlugin from "@elizaos/plugin-goat";
|
|
33
|
+
// import { intifacePlugin } from "@elizaos/plugin-intiface";
|
|
34
|
+
import { DirectClient } from "@elizaos/client-direct";
|
|
35
|
+
import { aptosPlugin } from "@elizaos/plugin-aptos";
|
|
36
|
+
import {
|
|
37
|
+
advancedTradePlugin,
|
|
38
|
+
coinbaseCommercePlugin,
|
|
39
|
+
coinbaseMassPaymentsPlugin,
|
|
40
|
+
tokenContractPlugin,
|
|
41
|
+
tradePlugin,
|
|
42
|
+
webhookPlugin,
|
|
43
|
+
} from "@elizaos/plugin-coinbase";
|
|
44
|
+
import { confluxPlugin } from "@elizaos/plugin-conflux";
|
|
45
|
+
import { evmPlugin } from "@elizaos/plugin-evm";
|
|
46
|
+
import { storyPlugin } from "@elizaos/plugin-story";
|
|
47
|
+
import { flowPlugin } from "@elizaos/plugin-flow";
|
|
48
|
+
import { imageGenerationPlugin } from "@elizaos/plugin-image-generation";
|
|
49
|
+
import { multiversxPlugin } from "@elizaos/plugin-multiversx";
|
|
50
|
+
import { nearPlugin } from "@elizaos/plugin-near";
|
|
51
|
+
import { nftGenerationPlugin } from "@elizaos/plugin-nft-generation";
|
|
52
|
+
import { createNodePlugin } from "@elizaos/plugin-node";
|
|
53
|
+
import { solanaPlugin } from "@elizaos/plugin-solana";
|
|
54
|
+
import { suiPlugin } from "@elizaos/plugin-sui";
|
|
55
|
+
import { TEEMode, teePlugin } from "@elizaos/plugin-tee";
|
|
56
|
+
import { tonPlugin } from "@elizaos/plugin-ton";
|
|
57
|
+
import { zksyncEraPlugin } from "@elizaos/plugin-zksync-era";
|
|
58
|
+
import Database from "better-sqlite3";
|
|
59
|
+
import fs from "fs";
|
|
60
|
+
import path from "path";
|
|
61
|
+
import { fileURLToPath } from "url";
|
|
62
|
+
import yargs from "yargs";
|
|
63
|
+
|
|
64
|
+
const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file
|
|
65
|
+
const __dirname = path.dirname(__filename); // get the name of the directory
|
|
66
|
+
|
|
67
|
+
export const wait = (minTime: number = 1000, maxTime: number = 3000) => {
|
|
68
|
+
const waitTime =
|
|
69
|
+
Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;
|
|
70
|
+
return new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const logFetch = async (url: string, options: any) => {
|
|
74
|
+
elizaLogger.debug(`Fetching ${url}`);
|
|
75
|
+
// Disabled to avoid disclosure of sensitive information such as API keys
|
|
76
|
+
// elizaLogger.debug(JSON.stringify(options, null, 2));
|
|
77
|
+
return fetch(url, options);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export function parseArguments(): {
|
|
81
|
+
character?: string;
|
|
82
|
+
characters?: string;
|
|
83
|
+
} {
|
|
84
|
+
try {
|
|
85
|
+
return yargs(process.argv.slice(3))
|
|
86
|
+
.option("character", {
|
|
87
|
+
type: "string",
|
|
88
|
+
description: "Path to the character JSON file",
|
|
89
|
+
})
|
|
90
|
+
.option("characters", {
|
|
91
|
+
type: "string",
|
|
92
|
+
description:
|
|
93
|
+
"Comma separated list of paths to character JSON files",
|
|
94
|
+
})
|
|
95
|
+
.parseSync();
|
|
96
|
+
} catch (error) {
|
|
97
|
+
elizaLogger.error("Error parsing arguments:", error);
|
|
98
|
+
return {};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function tryLoadFile(filePath: string): string | null {
|
|
103
|
+
try {
|
|
104
|
+
return fs.readFileSync(filePath, "utf8");
|
|
105
|
+
} catch (e) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function isAllStrings(arr: unknown[]): boolean {
|
|
111
|
+
return Array.isArray(arr) && arr.every((item) => typeof item === "string");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export async function loadCharacters(
|
|
115
|
+
charactersArg: string
|
|
116
|
+
): Promise<Character[]> {
|
|
117
|
+
let characterPaths = charactersArg
|
|
118
|
+
?.split(",")
|
|
119
|
+
.map((filePath) => filePath.trim());
|
|
120
|
+
const loadedCharacters = [];
|
|
121
|
+
|
|
122
|
+
if (characterPaths?.length > 0) {
|
|
123
|
+
for (const characterPath of characterPaths) {
|
|
124
|
+
let content = null;
|
|
125
|
+
let resolvedPath = "";
|
|
126
|
+
|
|
127
|
+
// Try different path resolutions in order
|
|
128
|
+
const pathsToTry = [
|
|
129
|
+
characterPath, // exact path as specified
|
|
130
|
+
path.resolve(process.cwd(), characterPath), // relative to cwd
|
|
131
|
+
path.resolve(process.cwd(), "agent", characterPath), // Add this
|
|
132
|
+
path.resolve(__dirname, characterPath), // relative to current script
|
|
133
|
+
path.resolve(
|
|
134
|
+
__dirname,
|
|
135
|
+
"characters",
|
|
136
|
+
path.basename(characterPath)
|
|
137
|
+
), // relative to agent/characters
|
|
138
|
+
path.resolve(
|
|
139
|
+
__dirname,
|
|
140
|
+
"../characters",
|
|
141
|
+
path.basename(characterPath)
|
|
142
|
+
), // relative to characters dir from agent
|
|
143
|
+
path.resolve(
|
|
144
|
+
__dirname,
|
|
145
|
+
"../../characters",
|
|
146
|
+
path.basename(characterPath)
|
|
147
|
+
), // relative to project root characters dir
|
|
148
|
+
];
|
|
149
|
+
|
|
150
|
+
elizaLogger.info(
|
|
151
|
+
"Trying paths:",
|
|
152
|
+
pathsToTry.map((p) => ({
|
|
153
|
+
path: p,
|
|
154
|
+
exists: fs.existsSync(p),
|
|
155
|
+
}))
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
for (const tryPath of pathsToTry) {
|
|
159
|
+
content = tryLoadFile(tryPath);
|
|
160
|
+
if (content !== null) {
|
|
161
|
+
resolvedPath = tryPath;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (content === null) {
|
|
167
|
+
elizaLogger.error(
|
|
168
|
+
`Error loading character from ${characterPath}: File not found in any of the expected locations`
|
|
169
|
+
);
|
|
170
|
+
elizaLogger.error("Tried the following paths:");
|
|
171
|
+
pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
const character = JSON.parse(content);
|
|
177
|
+
validateCharacterConfig(character);
|
|
178
|
+
|
|
179
|
+
// Handle plugins
|
|
180
|
+
if (isAllStrings(character.plugins)) {
|
|
181
|
+
elizaLogger.info("Plugins are: ", character.plugins);
|
|
182
|
+
const importedPlugins = await Promise.all(
|
|
183
|
+
character.plugins.map(async (plugin) => {
|
|
184
|
+
const importedPlugin = await import(plugin);
|
|
185
|
+
return importedPlugin.default;
|
|
186
|
+
})
|
|
187
|
+
);
|
|
188
|
+
character.plugins = importedPlugins;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
loadedCharacters.push(character);
|
|
192
|
+
elizaLogger.info(
|
|
193
|
+
`Successfully loaded character from: ${resolvedPath}`
|
|
194
|
+
);
|
|
195
|
+
} catch (e) {
|
|
196
|
+
elizaLogger.error(
|
|
197
|
+
`Error parsing character from ${resolvedPath}: ${e}`
|
|
198
|
+
);
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (loadedCharacters.length === 0) {
|
|
205
|
+
elizaLogger.info("No characters found, using default character");
|
|
206
|
+
loadedCharacters.push(defaultCharacter);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return loadedCharacters;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function getTokenForProvider(
|
|
213
|
+
provider: ModelProviderName,
|
|
214
|
+
character: Character
|
|
215
|
+
): string {
|
|
216
|
+
switch (provider) {
|
|
217
|
+
// no key needed for llama_local or gaianet
|
|
218
|
+
case ModelProviderName.LLAMALOCAL:
|
|
219
|
+
return "";
|
|
220
|
+
case ModelProviderName.OLLAMA:
|
|
221
|
+
return "";
|
|
222
|
+
case ModelProviderName.GAIANET:
|
|
223
|
+
return "";
|
|
224
|
+
case ModelProviderName.OPENAI:
|
|
225
|
+
return (
|
|
226
|
+
character.settings?.secrets?.OPENAI_API_KEY ||
|
|
227
|
+
settings.OPENAI_API_KEY
|
|
228
|
+
);
|
|
229
|
+
case ModelProviderName.ETERNALAI:
|
|
230
|
+
return (
|
|
231
|
+
character.settings?.secrets?.ETERNALAI_API_KEY ||
|
|
232
|
+
settings.ETERNALAI_API_KEY
|
|
233
|
+
);
|
|
234
|
+
case ModelProviderName.LLAMACLOUD:
|
|
235
|
+
case ModelProviderName.TOGETHER:
|
|
236
|
+
return (
|
|
237
|
+
character.settings?.secrets?.LLAMACLOUD_API_KEY ||
|
|
238
|
+
settings.LLAMACLOUD_API_KEY ||
|
|
239
|
+
character.settings?.secrets?.TOGETHER_API_KEY ||
|
|
240
|
+
settings.TOGETHER_API_KEY ||
|
|
241
|
+
character.settings?.secrets?.XAI_API_KEY ||
|
|
242
|
+
settings.XAI_API_KEY ||
|
|
243
|
+
character.settings?.secrets?.OPENAI_API_KEY ||
|
|
244
|
+
settings.OPENAI_API_KEY
|
|
245
|
+
);
|
|
246
|
+
case ModelProviderName.CLAUDE_VERTEX:
|
|
247
|
+
case ModelProviderName.ANTHROPIC:
|
|
248
|
+
return (
|
|
249
|
+
character.settings?.secrets?.ANTHROPIC_API_KEY ||
|
|
250
|
+
character.settings?.secrets?.CLAUDE_API_KEY ||
|
|
251
|
+
settings.ANTHROPIC_API_KEY ||
|
|
252
|
+
settings.CLAUDE_API_KEY
|
|
253
|
+
);
|
|
254
|
+
case ModelProviderName.REDPILL:
|
|
255
|
+
return (
|
|
256
|
+
character.settings?.secrets?.REDPILL_API_KEY ||
|
|
257
|
+
settings.REDPILL_API_KEY
|
|
258
|
+
);
|
|
259
|
+
case ModelProviderName.OPENROUTER:
|
|
260
|
+
return (
|
|
261
|
+
character.settings?.secrets?.OPENROUTER ||
|
|
262
|
+
settings.OPENROUTER_API_KEY
|
|
263
|
+
);
|
|
264
|
+
case ModelProviderName.GROK:
|
|
265
|
+
return (
|
|
266
|
+
character.settings?.secrets?.GROK_API_KEY ||
|
|
267
|
+
settings.GROK_API_KEY
|
|
268
|
+
);
|
|
269
|
+
case ModelProviderName.HEURIST:
|
|
270
|
+
return (
|
|
271
|
+
character.settings?.secrets?.HEURIST_API_KEY ||
|
|
272
|
+
settings.HEURIST_API_KEY
|
|
273
|
+
);
|
|
274
|
+
case ModelProviderName.GROQ:
|
|
275
|
+
return (
|
|
276
|
+
character.settings?.secrets?.GROQ_API_KEY ||
|
|
277
|
+
settings.GROQ_API_KEY
|
|
278
|
+
);
|
|
279
|
+
case ModelProviderName.GALADRIEL:
|
|
280
|
+
return (
|
|
281
|
+
character.settings?.secrets?.GALADRIEL_API_KEY ||
|
|
282
|
+
settings.GALADRIEL_API_KEY
|
|
283
|
+
);
|
|
284
|
+
case ModelProviderName.FAL:
|
|
285
|
+
return (
|
|
286
|
+
character.settings?.secrets?.FAL_API_KEY || settings.FAL_API_KEY
|
|
287
|
+
);
|
|
288
|
+
case ModelProviderName.ALI_BAILIAN:
|
|
289
|
+
return (
|
|
290
|
+
character.settings?.secrets?.ALI_BAILIAN_API_KEY ||
|
|
291
|
+
settings.ALI_BAILIAN_API_KEY
|
|
292
|
+
);
|
|
293
|
+
case ModelProviderName.VOLENGINE:
|
|
294
|
+
return (
|
|
295
|
+
character.settings?.secrets?.VOLENGINE_API_KEY ||
|
|
296
|
+
settings.VOLENGINE_API_KEY
|
|
297
|
+
);
|
|
298
|
+
case ModelProviderName.NANOGPT:
|
|
299
|
+
return (
|
|
300
|
+
character.settings?.secrets?.NANOGPT_API_KEY ||
|
|
301
|
+
settings.NANOGPT_API_KEY
|
|
302
|
+
);
|
|
303
|
+
case ModelProviderName.HYPERBOLIC:
|
|
304
|
+
return (
|
|
305
|
+
character.settings?.secrets?.HYPERBOLIC_API_KEY ||
|
|
306
|
+
settings.HYPERBOLIC_API_KEY
|
|
307
|
+
);
|
|
308
|
+
case ModelProviderName.VENICE:
|
|
309
|
+
return (
|
|
310
|
+
character.settings?.secrets?.VENICE_API_KEY ||
|
|
311
|
+
settings.VENICE_API_KEY
|
|
312
|
+
);
|
|
313
|
+
case ModelProviderName.AKASH_CHAT_API:
|
|
314
|
+
return (
|
|
315
|
+
character.settings?.secrets?.AKASH_CHAT_API_KEY ||
|
|
316
|
+
settings.AKASH_CHAT_API_KEY
|
|
317
|
+
);
|
|
318
|
+
case ModelProviderName.GOOGLE:
|
|
319
|
+
return (
|
|
320
|
+
character.settings?.secrets?.GOOGLE_GENERATIVE_AI_API_KEY ||
|
|
321
|
+
settings.GOOGLE_GENERATIVE_AI_API_KEY
|
|
322
|
+
);
|
|
323
|
+
default:
|
|
324
|
+
const errorMessage = `Failed to get token - unsupported model provider: ${provider}`;
|
|
325
|
+
elizaLogger.error(errorMessage);
|
|
326
|
+
throw new Error(errorMessage);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function initializeDatabase(dataDir: string) {
|
|
331
|
+
if (process.env.POSTGRES_URL) {
|
|
332
|
+
elizaLogger.info("Initializing PostgreSQL connection...");
|
|
333
|
+
const db = new PostgresDatabaseAdapter({
|
|
334
|
+
connectionString: process.env.POSTGRES_URL,
|
|
335
|
+
parseInputs: true,
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// Test the connection
|
|
339
|
+
db.init()
|
|
340
|
+
.then(() => {
|
|
341
|
+
elizaLogger.success(
|
|
342
|
+
"Successfully connected to PostgreSQL database"
|
|
343
|
+
);
|
|
344
|
+
})
|
|
345
|
+
.catch((error) => {
|
|
346
|
+
elizaLogger.error("Failed to connect to PostgreSQL:", error);
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
return db;
|
|
350
|
+
} else {
|
|
351
|
+
const filePath =
|
|
352
|
+
process.env.SQLITE_FILE ?? path.resolve(dataDir, "db.sqlite");
|
|
353
|
+
// ":memory:";
|
|
354
|
+
const db = new SqliteDatabaseAdapter(new Database(filePath));
|
|
355
|
+
return db;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// also adds plugins from character file into the runtime
|
|
360
|
+
export async function initializeClients(
|
|
361
|
+
character: Character,
|
|
362
|
+
runtime: IAgentRuntime
|
|
363
|
+
) {
|
|
364
|
+
// each client can only register once
|
|
365
|
+
// and if we want two we can explicitly support it
|
|
366
|
+
const clients: Record<string, any> = {};
|
|
367
|
+
const clientTypes: string[] =
|
|
368
|
+
character.clients?.map((str) => str.toLowerCase()) || [];
|
|
369
|
+
elizaLogger.log("initializeClients", clientTypes, "for", character.name);
|
|
370
|
+
|
|
371
|
+
if (clientTypes.includes(Clients.DIRECT)) {
|
|
372
|
+
const autoClient = await AutoClientInterface.start(runtime);
|
|
373
|
+
if (autoClient) clients.auto = autoClient;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (clientTypes.includes(Clients.DISCORD)) {
|
|
377
|
+
const discordClient = await DiscordClientInterface.start(runtime);
|
|
378
|
+
if (discordClient) clients.discord = discordClient;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (clientTypes.includes(Clients.TELEGRAM)) {
|
|
382
|
+
const telegramClient = await TelegramClientInterface.start(runtime);
|
|
383
|
+
if (telegramClient) clients.telegram = telegramClient;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (clientTypes.includes(Clients.TWITTER)) {
|
|
387
|
+
const twitterClient = await TwitterClientInterface.start(runtime);
|
|
388
|
+
|
|
389
|
+
if (twitterClient) {
|
|
390
|
+
clients.twitter = twitterClient;
|
|
391
|
+
(twitterClient as any).enableSearch = !isFalsish(
|
|
392
|
+
getSecret(character, "TWITTER_SEARCH_ENABLE")
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (clientTypes.includes(Clients.FARCASTER)) {
|
|
398
|
+
// why is this one different :(
|
|
399
|
+
const farcasterClient = new FarcasterAgentClient(runtime);
|
|
400
|
+
if (farcasterClient) {
|
|
401
|
+
farcasterClient.start();
|
|
402
|
+
clients.farcaster = farcasterClient;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
if (clientTypes.includes("lens")) {
|
|
406
|
+
const lensClient = new LensAgentClient(runtime);
|
|
407
|
+
lensClient.start();
|
|
408
|
+
clients.lens = lensClient;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
elizaLogger.log("client keys", Object.keys(clients));
|
|
412
|
+
|
|
413
|
+
// TODO: Add Slack client to the list
|
|
414
|
+
// Initialize clients as an object
|
|
415
|
+
|
|
416
|
+
if (clientTypes.includes("slack")) {
|
|
417
|
+
const slackClient = await SlackClientInterface.start(runtime);
|
|
418
|
+
if (slackClient) clients.slack = slackClient; // Use object property instead of push
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (character.plugins?.length > 0) {
|
|
422
|
+
for (const plugin of character.plugins) {
|
|
423
|
+
if (plugin.clients) {
|
|
424
|
+
for (const client of plugin.clients) {
|
|
425
|
+
const startedClient = await client.start(runtime);
|
|
426
|
+
clients[client.name] = startedClient; // Assuming client has a name property
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return clients;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function isFalsish(input: any): boolean {
|
|
436
|
+
// If the input is exactly NaN, return true
|
|
437
|
+
if (Number.isNaN(input)) {
|
|
438
|
+
return true;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Convert input to a string if it's not null or undefined
|
|
442
|
+
const value = input == null ? "" : String(input);
|
|
443
|
+
|
|
444
|
+
// List of common falsish string representations
|
|
445
|
+
const falsishValues = [
|
|
446
|
+
"false",
|
|
447
|
+
"0",
|
|
448
|
+
"no",
|
|
449
|
+
"n",
|
|
450
|
+
"off",
|
|
451
|
+
"null",
|
|
452
|
+
"undefined",
|
|
453
|
+
"",
|
|
454
|
+
];
|
|
455
|
+
|
|
456
|
+
// Check if the value (trimmed and lowercased) is in the falsish list
|
|
457
|
+
return falsishValues.includes(value.trim().toLowerCase());
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function getSecret(character: Character, secret: string) {
|
|
461
|
+
return character.settings?.secrets?.[secret] || process.env[secret];
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
let nodePlugin: any | undefined;
|
|
465
|
+
|
|
466
|
+
export async function createAgent(
|
|
467
|
+
character: Character,
|
|
468
|
+
db: IDatabaseAdapter,
|
|
469
|
+
cache: ICacheManager,
|
|
470
|
+
token: string
|
|
471
|
+
): Promise<AgentRuntime> {
|
|
472
|
+
elizaLogger.success(
|
|
473
|
+
elizaLogger.successesTitle,
|
|
474
|
+
"Creating runtime for character",
|
|
475
|
+
character.name
|
|
476
|
+
);
|
|
477
|
+
|
|
478
|
+
nodePlugin ??= createNodePlugin();
|
|
479
|
+
|
|
480
|
+
const teeMode = getSecret(character, "TEE_MODE") || "OFF";
|
|
481
|
+
const walletSecretSalt = getSecret(character, "WALLET_SECRET_SALT");
|
|
482
|
+
|
|
483
|
+
// Validate TEE configuration
|
|
484
|
+
if (teeMode !== TEEMode.OFF && !walletSecretSalt) {
|
|
485
|
+
elizaLogger.error(
|
|
486
|
+
"WALLET_SECRET_SALT required when TEE_MODE is enabled"
|
|
487
|
+
);
|
|
488
|
+
throw new Error("Invalid TEE configuration");
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
let goatPlugin: any | undefined;
|
|
492
|
+
if (getSecret(character, "ALCHEMY_API_KEY")) {
|
|
493
|
+
goatPlugin = await createGoatPlugin((secret) =>
|
|
494
|
+
getSecret(character, secret)
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
return new AgentRuntime({
|
|
499
|
+
databaseAdapter: db,
|
|
500
|
+
token,
|
|
501
|
+
modelProvider: character.modelProvider,
|
|
502
|
+
evaluators: [],
|
|
503
|
+
character,
|
|
504
|
+
// character.plugins are handled when clients are added
|
|
505
|
+
plugins: [
|
|
506
|
+
bootstrapPlugin,
|
|
507
|
+
getSecret(character, "CONFLUX_CORE_PRIVATE_KEY")
|
|
508
|
+
? confluxPlugin
|
|
509
|
+
: null,
|
|
510
|
+
nodePlugin,
|
|
511
|
+
getSecret(character, "SOLANA_PUBLIC_KEY") ||
|
|
512
|
+
(getSecret(character, "WALLET_PUBLIC_KEY") &&
|
|
513
|
+
!getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith("0x"))
|
|
514
|
+
? solanaPlugin
|
|
515
|
+
: null,
|
|
516
|
+
(getSecret(character, "NEAR_ADDRESS") ||
|
|
517
|
+
getSecret(character, "NEAR_WALLET_PUBLIC_KEY")) &&
|
|
518
|
+
getSecret(character, "NEAR_WALLET_SECRET_KEY")
|
|
519
|
+
? nearPlugin
|
|
520
|
+
: null,
|
|
521
|
+
getSecret(character, "EVM_PUBLIC_KEY") ||
|
|
522
|
+
(getSecret(character, "WALLET_PUBLIC_KEY") &&
|
|
523
|
+
getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith("0x"))
|
|
524
|
+
? evmPlugin
|
|
525
|
+
: null,
|
|
526
|
+
(getSecret(character, "SOLANA_PUBLIC_KEY") ||
|
|
527
|
+
(getSecret(character, "WALLET_PUBLIC_KEY") &&
|
|
528
|
+
!getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith(
|
|
529
|
+
"0x"
|
|
530
|
+
))) &&
|
|
531
|
+
getSecret(character, "SOLANA_ADMIN_PUBLIC_KEY") &&
|
|
532
|
+
getSecret(character, "SOLANA_PRIVATE_KEY") &&
|
|
533
|
+
getSecret(character, "SOLANA_ADMIN_PRIVATE_KEY")
|
|
534
|
+
? nftGenerationPlugin
|
|
535
|
+
: null,
|
|
536
|
+
getSecret(character, "ZEROG_PRIVATE_KEY") ? zgPlugin : null,
|
|
537
|
+
getSecret(character, "COINBASE_COMMERCE_KEY")
|
|
538
|
+
? coinbaseCommercePlugin
|
|
539
|
+
: null,
|
|
540
|
+
getSecret(character, "FAL_API_KEY") ||
|
|
541
|
+
getSecret(character, "OPENAI_API_KEY") ||
|
|
542
|
+
getSecret(character, "VENICE_API_KEY") ||
|
|
543
|
+
getSecret(character, "HEURIST_API_KEY")
|
|
544
|
+
? imageGenerationPlugin
|
|
545
|
+
: null,
|
|
546
|
+
...(getSecret(character, "COINBASE_API_KEY") &&
|
|
547
|
+
getSecret(character, "COINBASE_PRIVATE_KEY")
|
|
548
|
+
? [
|
|
549
|
+
coinbaseMassPaymentsPlugin,
|
|
550
|
+
tradePlugin,
|
|
551
|
+
tokenContractPlugin,
|
|
552
|
+
advancedTradePlugin,
|
|
553
|
+
]
|
|
554
|
+
: []),
|
|
555
|
+
...(teeMode !== TEEMode.OFF && walletSecretSalt
|
|
556
|
+
? [teePlugin, solanaPlugin]
|
|
557
|
+
: []),
|
|
558
|
+
getSecret(character, "COINBASE_API_KEY") &&
|
|
559
|
+
getSecret(character, "COINBASE_PRIVATE_KEY") &&
|
|
560
|
+
getSecret(character, "COINBASE_NOTIFICATION_URI")
|
|
561
|
+
? webhookPlugin
|
|
562
|
+
: null,
|
|
563
|
+
getSecret(character, "ALCHEMY_API_KEY") ? goatPlugin : null,
|
|
564
|
+
getSecret(character, "FLOW_ADDRESS") &&
|
|
565
|
+
getSecret(character, "FLOW_PRIVATE_KEY")
|
|
566
|
+
? flowPlugin
|
|
567
|
+
: null,
|
|
568
|
+
getSecret(character, "APTOS_PRIVATE_KEY") ? aptosPlugin : null,
|
|
569
|
+
getSecret(character, "MVX_PRIVATE_KEY") ? multiversxPlugin : null,
|
|
570
|
+
getSecret(character, "ZKSYNC_PRIVATE_KEY") ? zksyncEraPlugin : null,
|
|
571
|
+
getSecret(character, "TON_PRIVATE_KEY") ? tonPlugin : null,
|
|
572
|
+
getSecret(character, "SUI_PRIVATE_KEY") ? suiPlugin : null,
|
|
573
|
+
getSecret(character, "STORY_PRIVATE_KEY") ? storyPlugin : null,
|
|
574
|
+
].filter(Boolean),
|
|
575
|
+
providers: [],
|
|
576
|
+
actions: [],
|
|
577
|
+
services: [],
|
|
578
|
+
managers: [],
|
|
579
|
+
cacheManager: cache,
|
|
580
|
+
fetch: logFetch,
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function initializeFsCache(baseDir: string, character: Character) {
|
|
585
|
+
const cacheDir = path.resolve(baseDir, character.id, "cache");
|
|
586
|
+
|
|
587
|
+
const cache = new CacheManager(new FsCacheAdapter(cacheDir));
|
|
588
|
+
return cache;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
function initializeDbCache(character: Character, db: IDatabaseCacheAdapter) {
|
|
592
|
+
const cache = new CacheManager(new DbCacheAdapter(db, character.id));
|
|
593
|
+
return cache;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function initializeCache(
|
|
597
|
+
cacheStore: string,
|
|
598
|
+
character: Character,
|
|
599
|
+
baseDir?: string,
|
|
600
|
+
db?: IDatabaseCacheAdapter
|
|
601
|
+
) {
|
|
602
|
+
switch (cacheStore) {
|
|
603
|
+
case CacheStore.REDIS:
|
|
604
|
+
if (process.env.REDIS_URL) {
|
|
605
|
+
elizaLogger.info("Connecting to Redis...");
|
|
606
|
+
const redisClient = new RedisClient(process.env.REDIS_URL);
|
|
607
|
+
return new CacheManager(
|
|
608
|
+
new DbCacheAdapter(redisClient, character.id) // Using DbCacheAdapter since RedisClient also implements IDatabaseCacheAdapter
|
|
609
|
+
);
|
|
610
|
+
} else {
|
|
611
|
+
throw new Error("REDIS_URL environment variable is not set.");
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
case CacheStore.DATABASE:
|
|
615
|
+
if (db) {
|
|
616
|
+
elizaLogger.info("Using Database Cache...");
|
|
617
|
+
return initializeDbCache(character, db);
|
|
618
|
+
} else {
|
|
619
|
+
throw new Error(
|
|
620
|
+
"Database adapter is not provided for CacheStore.Database."
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
case CacheStore.FILESYSTEM:
|
|
625
|
+
elizaLogger.info("Using File System Cache...");
|
|
626
|
+
return initializeFsCache(baseDir, character);
|
|
627
|
+
|
|
628
|
+
default:
|
|
629
|
+
throw new Error(
|
|
630
|
+
`Invalid cache store: ${cacheStore} or required configuration missing.`
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
async function startAgent(
|
|
636
|
+
character: Character,
|
|
637
|
+
directClient: DirectClient
|
|
638
|
+
): Promise<AgentRuntime> {
|
|
639
|
+
let db: IDatabaseAdapter & IDatabaseCacheAdapter;
|
|
640
|
+
try {
|
|
641
|
+
character.id ??= stringToUuid(character.name);
|
|
642
|
+
character.username ??= character.name;
|
|
643
|
+
|
|
644
|
+
const token = getTokenForProvider(character.modelProvider, character);
|
|
645
|
+
const dataDir = path.join(__dirname, "../data");
|
|
646
|
+
|
|
647
|
+
if (!fs.existsSync(dataDir)) {
|
|
648
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
db = initializeDatabase(dataDir) as IDatabaseAdapter &
|
|
652
|
+
IDatabaseCacheAdapter;
|
|
653
|
+
|
|
654
|
+
await db.init();
|
|
655
|
+
|
|
656
|
+
const cache = initializeCache(
|
|
657
|
+
process.env.CACHE_STORE ?? CacheStore.DATABASE,
|
|
658
|
+
character,
|
|
659
|
+
"",
|
|
660
|
+
db
|
|
661
|
+
); // "" should be replaced with dir for file system caching. THOUGHTS: might probably make this into an env
|
|
662
|
+
const runtime: AgentRuntime = await createAgent(
|
|
663
|
+
character,
|
|
664
|
+
db,
|
|
665
|
+
cache,
|
|
666
|
+
token
|
|
667
|
+
);
|
|
668
|
+
|
|
669
|
+
// start services/plugins/process knowledge
|
|
670
|
+
await runtime.initialize();
|
|
671
|
+
|
|
672
|
+
// start assigned clients
|
|
673
|
+
runtime.clients = await initializeClients(character, runtime);
|
|
674
|
+
|
|
675
|
+
// add to container
|
|
676
|
+
directClient.registerAgent(runtime);
|
|
677
|
+
|
|
678
|
+
// report to console
|
|
679
|
+
elizaLogger.debug(`Started ${character.name} as ${runtime.agentId}`);
|
|
680
|
+
|
|
681
|
+
return runtime;
|
|
682
|
+
} catch (error) {
|
|
683
|
+
elizaLogger.error(
|
|
684
|
+
`Error starting agent for character ${character.name}:`,
|
|
685
|
+
error
|
|
686
|
+
);
|
|
687
|
+
elizaLogger.error(error);
|
|
688
|
+
if (db) {
|
|
689
|
+
await db.close();
|
|
690
|
+
}
|
|
691
|
+
throw error;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
const startAgents = async () => {
|
|
696
|
+
const directClient = new DirectClient();
|
|
697
|
+
const serverPort = parseInt(settings.SERVER_PORT || "3000");
|
|
698
|
+
const args = parseArguments();
|
|
699
|
+
|
|
700
|
+
let charactersArg = args.characters || args.character;
|
|
701
|
+
|
|
702
|
+
let characters = [defaultCharacter];
|
|
703
|
+
|
|
704
|
+
if (charactersArg) {
|
|
705
|
+
characters = await loadCharacters(charactersArg);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
try {
|
|
709
|
+
for (const character of characters) {
|
|
710
|
+
await startAgent(character, directClient);
|
|
711
|
+
}
|
|
712
|
+
} catch (error) {
|
|
713
|
+
elizaLogger.error("Error starting agents:", error);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// upload some agent functionality into directClient
|
|
717
|
+
directClient.startAgent = async (character: Character) => {
|
|
718
|
+
// wrap it so we don't have to inject directClient later
|
|
719
|
+
return startAgent(character, directClient);
|
|
720
|
+
};
|
|
721
|
+
directClient.start(serverPort);
|
|
722
|
+
|
|
723
|
+
elizaLogger.log(
|
|
724
|
+
"Run `pnpm start:client` to start the client and visit the outputted URL (http://localhost:5173) to chat with your agents"
|
|
725
|
+
);
|
|
726
|
+
};
|
|
727
|
+
|
|
728
|
+
startAgents().catch((error) => {
|
|
729
|
+
elizaLogger.error("Unhandled error in startAgents:", error);
|
|
730
|
+
process.exit(1); // Exit the process after logging
|
|
731
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../packages/core/tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "dist",
|
|
5
|
+
"rootDir": ".",
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"moduleResolution": "Bundler",
|
|
8
|
+
"types": [
|
|
9
|
+
"node"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"ts-node": {
|
|
13
|
+
"experimentalSpecifierResolution": "node",
|
|
14
|
+
"transpileOnly": true,
|
|
15
|
+
"esm": true,
|
|
16
|
+
},
|
|
17
|
+
"include": [
|
|
18
|
+
"src"
|
|
19
|
+
]
|
|
20
|
+
}
|