@exagent/agent 0.1.0
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/dist/chunk-6LDEQK7Q.mjs +986 -0
- package/dist/chunk-DRHO56RO.mjs +986 -0
- package/dist/chunk-GO5SB4LS.mjs +986 -0
- package/dist/chunk-JHXVT7PE.mjs +1090 -0
- package/dist/chunk-JMDWVGDG.mjs +986 -0
- package/dist/chunk-JS7RJORF.mjs +1548 -0
- package/dist/chunk-NTGO2FIV.mjs +1121 -0
- package/dist/chunk-XCTKJAV6.mjs +1061 -0
- package/dist/chunk-ZJ7JS4V6.mjs +986 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +1828 -0
- package/dist/cli.mjs +322 -0
- package/dist/index.d.mts +673 -0
- package/dist/index.d.ts +673 -0
- package/dist/index.js +1607 -0
- package/dist/index.mjs +54 -0
- package/package.json +52 -0
- package/templates/.env.template +55 -0
- package/templates/docker-compose.yml +60 -0
- package/templates/strategy.template.ts +153 -0
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
AgentRuntime,
|
|
4
|
+
getAllStrategyTemplates,
|
|
5
|
+
loadConfig,
|
|
6
|
+
validateConfig
|
|
7
|
+
} from "./chunk-JS7RJORF.mjs";
|
|
8
|
+
|
|
9
|
+
// src/cli.ts
|
|
10
|
+
import { Command } from "commander";
|
|
11
|
+
import { config as loadEnvFile } from "dotenv";
|
|
12
|
+
import * as readline from "readline";
|
|
13
|
+
import * as fs from "fs";
|
|
14
|
+
import * as path from "path";
|
|
15
|
+
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
|
|
16
|
+
loadEnvFile();
|
|
17
|
+
var program = new Command();
|
|
18
|
+
program.name("exagent").description("Exagent autonomous trading agent").version("0.1.0");
|
|
19
|
+
function prompt(question, hidden = false) {
|
|
20
|
+
const rl = readline.createInterface({
|
|
21
|
+
input: process.stdin,
|
|
22
|
+
output: process.stdout
|
|
23
|
+
});
|
|
24
|
+
return new Promise((resolve) => {
|
|
25
|
+
if (hidden) {
|
|
26
|
+
process.stdout.write(question);
|
|
27
|
+
let input = "";
|
|
28
|
+
process.stdin.setRawMode(true);
|
|
29
|
+
process.stdin.resume();
|
|
30
|
+
process.stdin.setEncoding("utf8");
|
|
31
|
+
const onData = (char) => {
|
|
32
|
+
if (char === "\n" || char === "\r") {
|
|
33
|
+
process.stdin.setRawMode(false);
|
|
34
|
+
process.stdin.pause();
|
|
35
|
+
process.stdin.removeListener("data", onData);
|
|
36
|
+
console.log("");
|
|
37
|
+
rl.close();
|
|
38
|
+
resolve(input);
|
|
39
|
+
} else if (char === "") {
|
|
40
|
+
process.exit(0);
|
|
41
|
+
} else if (char === "\x7F") {
|
|
42
|
+
if (input.length > 0) {
|
|
43
|
+
input = input.slice(0, -1);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
input += char;
|
|
47
|
+
process.stdout.write("*");
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
process.stdin.on("data", onData);
|
|
51
|
+
} else {
|
|
52
|
+
rl.question(question, (answer) => {
|
|
53
|
+
rl.close();
|
|
54
|
+
resolve(answer);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async function checkFirstRunSetup(configPath) {
|
|
60
|
+
const envPath = path.join(path.dirname(configPath), ".env");
|
|
61
|
+
if (fs.existsSync(envPath)) {
|
|
62
|
+
const envContent2 = fs.readFileSync(envPath, "utf-8");
|
|
63
|
+
const hasPrivateKey = envContent2.includes("EXAGENT_PRIVATE_KEY=") && !envContent2.includes("EXAGENT_PRIVATE_KEY=\n") && !envContent2.includes("EXAGENT_PRIVATE_KEY=$");
|
|
64
|
+
if (hasPrivateKey) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const config = loadConfig(configPath);
|
|
69
|
+
const walletSetup = config.wallet?.setup || "provide";
|
|
70
|
+
console.log("");
|
|
71
|
+
console.log("=".repeat(60));
|
|
72
|
+
console.log(" EXAGENT FIRST-RUN SETUP");
|
|
73
|
+
console.log("=".repeat(60));
|
|
74
|
+
console.log("");
|
|
75
|
+
console.log(" This appears to be your first time running this agent.");
|
|
76
|
+
console.log(" Let's set up your wallet and API keys.");
|
|
77
|
+
console.log("");
|
|
78
|
+
console.log(" Your secrets will be stored locally in .env");
|
|
79
|
+
console.log(" They are NEVER sent to Exagent servers.");
|
|
80
|
+
console.log("");
|
|
81
|
+
console.log("=".repeat(60));
|
|
82
|
+
console.log("");
|
|
83
|
+
let privateKey;
|
|
84
|
+
let walletAddress;
|
|
85
|
+
if (walletSetup === "generate") {
|
|
86
|
+
console.log("[WALLET] Generating a new wallet for your agent...");
|
|
87
|
+
console.log("");
|
|
88
|
+
const generatedKey = generatePrivateKey();
|
|
89
|
+
const account = privateKeyToAccount(generatedKey);
|
|
90
|
+
privateKey = generatedKey;
|
|
91
|
+
walletAddress = account.address;
|
|
92
|
+
console.log(" New wallet created!");
|
|
93
|
+
console.log("");
|
|
94
|
+
console.log(" +" + "-".repeat(58) + "+");
|
|
95
|
+
console.log(" | WALLET ADDRESS (fund this to start trading): |");
|
|
96
|
+
console.log(" | " + walletAddress.padEnd(56) + " |");
|
|
97
|
+
console.log(" +" + "-".repeat(58) + "+");
|
|
98
|
+
console.log("");
|
|
99
|
+
console.log(" IMPORTANT: Your private key has been saved to .env");
|
|
100
|
+
console.log(" Back up this file securely. If lost, your funds are gone.");
|
|
101
|
+
console.log("");
|
|
102
|
+
const confirmed = await prompt(" Press Enter to continue, or Ctrl+C to cancel...");
|
|
103
|
+
} else {
|
|
104
|
+
console.log("[WALLET] Please enter your trading wallet private key.");
|
|
105
|
+
console.log("");
|
|
106
|
+
console.log(" Your input will be hidden for security.");
|
|
107
|
+
console.log(" The key should start with 0x and be 66 characters total.");
|
|
108
|
+
console.log("");
|
|
109
|
+
privateKey = await prompt(" Private key: ", true);
|
|
110
|
+
if (!privateKey.startsWith("0x")) {
|
|
111
|
+
privateKey = "0x" + privateKey;
|
|
112
|
+
}
|
|
113
|
+
if (privateKey.length !== 66) {
|
|
114
|
+
console.error("");
|
|
115
|
+
console.error(" ERROR: Invalid private key length. Expected 66 characters (with 0x prefix).");
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
const account = privateKeyToAccount(privateKey);
|
|
120
|
+
walletAddress = account.address;
|
|
121
|
+
console.log("");
|
|
122
|
+
console.log(` Wallet address: ${walletAddress}`);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error("");
|
|
125
|
+
console.error(" ERROR: Invalid private key format.");
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
console.log("");
|
|
130
|
+
const llmProvider = config.llm?.provider || "openai";
|
|
131
|
+
let llmApiKey = "";
|
|
132
|
+
let llmEnvVar = "";
|
|
133
|
+
if (llmProvider === "ollama") {
|
|
134
|
+
console.log("[LLM] Using Ollama (local). No API key needed.");
|
|
135
|
+
console.log(" Make sure Ollama is running: ollama serve");
|
|
136
|
+
console.log("");
|
|
137
|
+
} else if (llmProvider === "custom") {
|
|
138
|
+
console.log("[LLM] Using custom OpenAI-compatible endpoint.");
|
|
139
|
+
console.log("");
|
|
140
|
+
const llmUrl = await prompt(" Enter your API endpoint URL: ");
|
|
141
|
+
llmApiKey = await prompt(" Enter your API key (or press Enter if none): ", true);
|
|
142
|
+
llmEnvVar = `EXAGENT_LLM_URL=${llmUrl}
|
|
143
|
+
`;
|
|
144
|
+
if (llmApiKey) {
|
|
145
|
+
llmEnvVar += `EXAGENT_LLM_API_KEY=${llmApiKey}
|
|
146
|
+
`;
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
const providerNames = {
|
|
150
|
+
openai: { name: "OpenAI", envVar: "OPENAI_API_KEY", url: "https://platform.openai.com/api-keys" },
|
|
151
|
+
anthropic: { name: "Anthropic", envVar: "ANTHROPIC_API_KEY", url: "https://console.anthropic.com/settings/keys" },
|
|
152
|
+
google: { name: "Google AI", envVar: "GOOGLE_AI_API_KEY", url: "https://aistudio.google.com/apikey" },
|
|
153
|
+
deepseek: { name: "DeepSeek", envVar: "DEEPSEEK_API_KEY", url: "https://platform.deepseek.com/api_keys" },
|
|
154
|
+
mistral: { name: "Mistral AI", envVar: "MISTRAL_API_KEY", url: "https://console.mistral.ai/api-keys/" },
|
|
155
|
+
groq: { name: "Groq", envVar: "GROQ_API_KEY", url: "https://console.groq.com/keys" },
|
|
156
|
+
together: { name: "Together AI", envVar: "TOGETHER_API_KEY", url: "https://api.together.xyz/settings/api-keys" }
|
|
157
|
+
};
|
|
158
|
+
const provider = providerNames[llmProvider] || providerNames.openai;
|
|
159
|
+
console.log(`[LLM] Enter your ${provider.name} API key.`);
|
|
160
|
+
console.log(` Get one at: ${provider.url}`);
|
|
161
|
+
console.log("");
|
|
162
|
+
llmApiKey = await prompt(" API key: ", true);
|
|
163
|
+
if (!llmApiKey) {
|
|
164
|
+
console.error("");
|
|
165
|
+
console.error(" ERROR: API key is required.");
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
168
|
+
llmEnvVar = `${provider.envVar}=${llmApiKey}
|
|
169
|
+
`;
|
|
170
|
+
}
|
|
171
|
+
const envContent = `# Exagent Agent Configuration
|
|
172
|
+
# Agent: ${config.name}
|
|
173
|
+
# Agent ID: ${config.agentId}
|
|
174
|
+
# Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
175
|
+
# WARNING: Never commit this file to version control!
|
|
176
|
+
|
|
177
|
+
# Wallet
|
|
178
|
+
EXAGENT_PRIVATE_KEY=${privateKey}
|
|
179
|
+
|
|
180
|
+
# Network
|
|
181
|
+
EXAGENT_NETWORK=${config.network || "testnet"}
|
|
182
|
+
|
|
183
|
+
# LLM (${llmProvider})
|
|
184
|
+
${llmEnvVar}EXAGENT_LLM_MODEL=${config.llm?.model || ""}
|
|
185
|
+
`;
|
|
186
|
+
fs.writeFileSync(envPath, envContent, { mode: 384 });
|
|
187
|
+
console.log("");
|
|
188
|
+
console.log("=".repeat(60));
|
|
189
|
+
console.log(" SETUP COMPLETE");
|
|
190
|
+
console.log("=".repeat(60));
|
|
191
|
+
console.log("");
|
|
192
|
+
console.log(" Your .env file has been created.");
|
|
193
|
+
console.log("");
|
|
194
|
+
console.log(` Wallet: ${walletAddress}`);
|
|
195
|
+
console.log(` LLM: ${llmProvider}`);
|
|
196
|
+
console.log("");
|
|
197
|
+
if (walletSetup === "generate") {
|
|
198
|
+
console.log(" NEXT: Fund your wallet before starting to trade.");
|
|
199
|
+
console.log(` Send testnet ETH to: ${walletAddress}`);
|
|
200
|
+
}
|
|
201
|
+
console.log("");
|
|
202
|
+
console.log(" The agent will now start...");
|
|
203
|
+
console.log("");
|
|
204
|
+
loadEnvFile({ path: envPath, override: true });
|
|
205
|
+
}
|
|
206
|
+
program.command("run").description("Start the trading agent").option("-c, --config <path>", "Path to agent-config.json", "agent-config.json").action(async (options) => {
|
|
207
|
+
try {
|
|
208
|
+
await checkFirstRunSetup(options.config);
|
|
209
|
+
console.log("Loading configuration...");
|
|
210
|
+
const config = loadConfig(options.config);
|
|
211
|
+
validateConfig(config);
|
|
212
|
+
console.log("");
|
|
213
|
+
console.log("=".repeat(50));
|
|
214
|
+
console.log(" EXAGENT TRADING AGENT");
|
|
215
|
+
console.log("=".repeat(50));
|
|
216
|
+
console.log("");
|
|
217
|
+
console.log(` Agent: ${config.name} (ID: ${config.agentId})`);
|
|
218
|
+
console.log(` Network: ${config.network}`);
|
|
219
|
+
console.log(` LLM: ${config.llm.provider} (${config.llm.model || "default"})`);
|
|
220
|
+
console.log(` Universe: ${config.riskUniverse}`);
|
|
221
|
+
console.log("");
|
|
222
|
+
console.log("=".repeat(50));
|
|
223
|
+
console.log("");
|
|
224
|
+
const agent = new AgentRuntime(config);
|
|
225
|
+
await agent.initialize();
|
|
226
|
+
process.on("SIGINT", () => {
|
|
227
|
+
console.log("\nReceived SIGINT, shutting down...");
|
|
228
|
+
agent.stop();
|
|
229
|
+
process.exit(0);
|
|
230
|
+
});
|
|
231
|
+
process.on("SIGTERM", () => {
|
|
232
|
+
console.log("\nReceived SIGTERM, shutting down...");
|
|
233
|
+
agent.stop();
|
|
234
|
+
process.exit(0);
|
|
235
|
+
});
|
|
236
|
+
await agent.run();
|
|
237
|
+
} catch (error) {
|
|
238
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
program.command("templates").description("List available strategy templates").action(() => {
|
|
243
|
+
console.log("");
|
|
244
|
+
console.log("Available Strategy Templates:");
|
|
245
|
+
console.log("=".repeat(50));
|
|
246
|
+
console.log("");
|
|
247
|
+
const templates = getAllStrategyTemplates();
|
|
248
|
+
for (const template of templates) {
|
|
249
|
+
console.log(`${template.id.toUpperCase()}`);
|
|
250
|
+
console.log(` Name: ${template.name}`);
|
|
251
|
+
console.log(` Risk: ${template.riskLevel}`);
|
|
252
|
+
console.log(` ${template.description}`);
|
|
253
|
+
console.log("");
|
|
254
|
+
console.log(" Warnings:");
|
|
255
|
+
for (const warning of template.riskWarnings) {
|
|
256
|
+
console.log(` - ${warning}`);
|
|
257
|
+
}
|
|
258
|
+
console.log("");
|
|
259
|
+
console.log("-".repeat(50));
|
|
260
|
+
console.log("");
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
program.command("status").description("Check agent configuration status").option("-c, --config <path>", "Path to agent-config.json", "agent-config.json").action(async (options) => {
|
|
264
|
+
try {
|
|
265
|
+
const config = loadConfig(options.config);
|
|
266
|
+
validateConfig(config);
|
|
267
|
+
console.log("");
|
|
268
|
+
console.log("Agent Configuration:");
|
|
269
|
+
console.log("=".repeat(50));
|
|
270
|
+
console.log(` Agent ID: ${config.agentId}`);
|
|
271
|
+
console.log(` Name: ${config.name}`);
|
|
272
|
+
console.log(` Network: ${config.network}`);
|
|
273
|
+
console.log(` LLM: ${config.llm.provider} (${config.llm.model || "default"})`);
|
|
274
|
+
console.log(` Universe: ${config.riskUniverse}`);
|
|
275
|
+
console.log("");
|
|
276
|
+
console.log("Trading Config:");
|
|
277
|
+
console.log(` Horizon: ${config.trading.timeHorizon}`);
|
|
278
|
+
console.log(` Max Position: ${config.trading.maxPositionSizeBps / 100}%`);
|
|
279
|
+
console.log(` Max Daily Loss: ${config.trading.maxDailyLossBps / 100}%`);
|
|
280
|
+
console.log(` Interval: ${config.trading.tradingIntervalMs}ms`);
|
|
281
|
+
console.log("");
|
|
282
|
+
console.log("Configuration is valid.");
|
|
283
|
+
} catch (error) {
|
|
284
|
+
console.error("Configuration error:", error instanceof Error ? error.message : error);
|
|
285
|
+
process.exit(1);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
program.command("api-keys").description("Show how to get API keys for each LLM provider").action(() => {
|
|
289
|
+
console.log("");
|
|
290
|
+
console.log("LLM Provider API Keys:");
|
|
291
|
+
console.log("=".repeat(50));
|
|
292
|
+
console.log("");
|
|
293
|
+
console.log("OPENAI");
|
|
294
|
+
console.log(" Get your API key at: https://platform.openai.com/api-keys");
|
|
295
|
+
console.log("");
|
|
296
|
+
console.log("ANTHROPIC");
|
|
297
|
+
console.log(" Get your API key at: https://console.anthropic.com/settings/keys");
|
|
298
|
+
console.log("");
|
|
299
|
+
console.log("DEEPSEEK");
|
|
300
|
+
console.log(" Get your API key at: https://platform.deepseek.com/api_keys");
|
|
301
|
+
console.log("");
|
|
302
|
+
console.log("GOOGLE AI");
|
|
303
|
+
console.log(" Get your API key at: https://aistudio.google.com/apikey");
|
|
304
|
+
console.log("");
|
|
305
|
+
console.log("MISTRAL AI");
|
|
306
|
+
console.log(" Get your API key at: https://console.mistral.ai/api-keys/");
|
|
307
|
+
console.log("");
|
|
308
|
+
console.log("GROQ");
|
|
309
|
+
console.log(" Get your API key at: https://console.groq.com/keys");
|
|
310
|
+
console.log("");
|
|
311
|
+
console.log("TOGETHER AI");
|
|
312
|
+
console.log(" Get your API key at: https://api.together.xyz/settings/api-keys");
|
|
313
|
+
console.log("");
|
|
314
|
+
console.log("OLLAMA (Local - No API Key Required)");
|
|
315
|
+
console.log(" Install: https://ollama.com/download");
|
|
316
|
+
console.log(" Run: ollama serve");
|
|
317
|
+
console.log(" Pull model: ollama pull mistral");
|
|
318
|
+
console.log("");
|
|
319
|
+
console.log("Note: Your API keys are stored locally in .env and never sent to Exagent servers.");
|
|
320
|
+
console.log("");
|
|
321
|
+
});
|
|
322
|
+
program.parse();
|