nyxora 26.6.21 → 26.6.23
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/README.md +3 -4
- package/bin/nyxora.mjs +14 -2
- package/dist/packages/core/src/agent/cronManager.js +107 -0
- package/dist/packages/core/src/agent/reasoning.js +85 -22
- package/dist/packages/core/src/agent/transactionManager.js +2 -2
- package/dist/packages/core/src/agent/updateIdentity.js +71 -0
- package/dist/packages/core/src/config/paths.js +5 -20
- package/dist/packages/core/src/gateway/WebSocketManager.js +98 -0
- package/dist/packages/core/src/gateway/chat.js +38 -0
- package/dist/packages/core/src/gateway/cli.js +20 -20
- package/dist/packages/core/src/gateway/server.js +63 -8
- package/dist/packages/core/src/gateway/setup.js +9 -6
- package/dist/packages/core/src/gateway/telegram.js +43 -0
- package/dist/packages/core/src/gateway/tracker.js +63 -0
- package/dist/packages/core/src/memory/logger.js +1 -1
- package/dist/packages/core/src/system/skills/cancelTask.js +40 -0
- package/dist/packages/core/src/system/skills/editFile.js +5 -0
- package/dist/packages/core/src/system/skills/scheduleTask.js +39 -0
- package/dist/packages/core/src/system/skills/searchWeb.js +61 -8
- package/dist/packages/core/src/system/skills/writeFile.js +5 -0
- package/dist/packages/core/src/web3/skills/getPrice.js +1 -1
- package/dist/packages/core/src/web3/utils/vaultClient.js +79 -29
- package/dist/packages/policy/src/server.js +29 -1
- package/package.json +7 -1
- package/packages/core/package.json +8 -1
- package/packages/core/src/agent/cronManager.ts +87 -0
- package/packages/core/src/agent/reasoning.ts +91 -21
- package/packages/core/src/agent/transactionManager.ts +2 -1
- package/packages/core/src/agent/updateIdentity.ts +68 -0
- package/packages/core/src/config/parser.ts +1 -1
- package/packages/core/src/config/paths.ts +5 -23
- package/packages/core/src/gateway/WebSocketManager.ts +114 -0
- package/packages/core/src/gateway/chat.ts +40 -1
- package/packages/core/src/gateway/cli.ts +10 -10
- package/packages/core/src/gateway/server.ts +66 -7
- package/packages/core/src/gateway/setup.ts +8 -5
- package/packages/core/src/gateway/telegram.ts +49 -0
- package/packages/core/src/gateway/tracker.ts +61 -0
- package/packages/core/src/memory/logger.ts +1 -1
- package/packages/core/src/system/skills/cancelTask.ts +38 -0
- package/packages/core/src/system/skills/editFile.ts +7 -0
- package/packages/core/src/system/skills/scheduleTask.ts +38 -0
- package/packages/core/src/system/skills/searchWeb.ts +56 -8
- package/packages/core/src/system/skills/writeFile.ts +7 -0
- package/packages/core/src/web3/skills/getPrice.ts +1 -1
- package/packages/core/src/web3/utils/vaultClient.ts +86 -26
- package/packages/dashboard/dist/assets/index-CjZWf1Ei.css +1 -0
- package/packages/dashboard/dist/assets/index-CmWZofn_.js +16 -0
- package/packages/dashboard/dist/index.html +2 -2
- package/packages/dashboard/dist/routers/0x.png +0 -0
- package/packages/dashboard/dist/routers/1inch.png +0 -0
- package/packages/dashboard/dist/routers/cmc.png +0 -0
- package/packages/dashboard/dist/routers/kyberswap.png +0 -0
- package/packages/dashboard/dist/routers/lifi.png +0 -0
- package/packages/dashboard/dist/routers/openocean.png +0 -0
- package/packages/dashboard/dist/routers/relay.png +0 -0
- package/packages/dashboard/dist/routers/zerion.png +0 -0
- package/packages/dashboard/package.json +1 -1
- package/packages/mcp-server/package.json +1 -1
- package/packages/policy/package.json +4 -3
- package/packages/policy/src/server.ts +29 -1
- package/packages/signer/package.json +1 -1
- package/packages/dashboard/dist/assets/index-CQNHWZtN.css +0 -1
- package/packages/dashboard/dist/assets/index-Di9x08yk.js +0 -16
|
@@ -52,7 +52,6 @@ const parser_1 = require("../config/parser");
|
|
|
52
52
|
async function main() {
|
|
53
53
|
// 1. Determine configuration directory
|
|
54
54
|
const appDir = (0, paths_1.getAppDir)();
|
|
55
|
-
const isGlobalMode = appDir !== process.cwd();
|
|
56
55
|
console.log(`================================`);
|
|
57
56
|
console.log(`🤖 Nyxora CLI Agent Booting Up...`);
|
|
58
57
|
console.log(`📂 Config Directory: ${appDir}`);
|
|
@@ -219,30 +218,31 @@ async function main() {
|
|
|
219
218
|
console.log(picocolors_1.default.green(' npm uninstall -g nyxora\n'));
|
|
220
219
|
process.exit(0);
|
|
221
220
|
}
|
|
222
|
-
// 2. Setup boilerplate files
|
|
221
|
+
// 2. Setup boilerplate files since we enforce global mode
|
|
223
222
|
let isFirstBoot = false;
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
fs_1.default.copyFileSync(exampleConfigPath, globalConfigPath);
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
fs_1.default.writeFileSync(globalConfigPath, 'agent:\n name: Nyxora-Agent\n default_chain: base\nllm:\n provider: openai\n model: gpt-4\n temperature: 0.7\nmemory:\n type: file\n path: memory.json\n');
|
|
237
|
-
}
|
|
223
|
+
const globalConfigPath = (0, paths_1.getPath)('config.yaml');
|
|
224
|
+
const globalUserMdPath = (0, paths_1.getPath)('user.md');
|
|
225
|
+
const globalIdentityMdPath = (0, paths_1.getPath)('IDENTITY.md');
|
|
226
|
+
// Copy default config.yaml
|
|
227
|
+
if (!fs_1.default.existsSync(globalConfigPath)) {
|
|
228
|
+
isFirstBoot = true;
|
|
229
|
+
let exampleConfigPath = path_1.default.resolve(__dirname, '../../../config.yaml'); // Dev
|
|
230
|
+
if (!fs_1.default.existsSync(exampleConfigPath)) {
|
|
231
|
+
exampleConfigPath = path_1.default.resolve(__dirname, '../../../../../config.yaml'); // Compiled
|
|
238
232
|
}
|
|
239
|
-
if (
|
|
240
|
-
fs_1.default.
|
|
233
|
+
if (fs_1.default.existsSync(exampleConfigPath)) {
|
|
234
|
+
fs_1.default.copyFileSync(exampleConfigPath, globalConfigPath);
|
|
241
235
|
}
|
|
242
|
-
|
|
243
|
-
fs_1.default.writeFileSync(
|
|
236
|
+
else {
|
|
237
|
+
fs_1.default.writeFileSync(globalConfigPath, 'agent:\n name: Nyxora-Agent\n default_chain: base\nllm:\n provider: openai\n model: gpt-4\n temperature: 0.7\nmemory:\n type: file\n path: memory.json\n');
|
|
244
238
|
}
|
|
245
239
|
}
|
|
240
|
+
if (!fs_1.default.existsSync(globalUserMdPath)) {
|
|
241
|
+
fs_1.default.writeFileSync(globalUserMdPath, 'Write custom instructions, special rules, user profiles, or the persona you want for Nyxora AI in this file.\n');
|
|
242
|
+
}
|
|
243
|
+
if (!fs_1.default.existsSync(globalIdentityMdPath)) {
|
|
244
|
+
fs_1.default.writeFileSync(globalIdentityMdPath, 'You are a Web3 AI assistant named Nyxora.\n');
|
|
245
|
+
}
|
|
246
246
|
if (isFirstBoot) {
|
|
247
247
|
console.log('[Setup] New installation detected. Starting Setup Wizard...');
|
|
248
248
|
await (0, setup_1.runSetupWizard)();
|
|
@@ -18,8 +18,11 @@ process.on('uncaughtException', (error) => {
|
|
|
18
18
|
const path_1 = __importDefault(require("path"));
|
|
19
19
|
const helmet_1 = __importDefault(require("helmet"));
|
|
20
20
|
const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
|
|
21
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
22
|
+
const os_1 = __importDefault(require("os"));
|
|
21
23
|
const paths_1 = require("../config/paths");
|
|
22
24
|
const state_1 = require("../utils/state");
|
|
25
|
+
const WebSocketManager_1 = require("./WebSocketManager");
|
|
23
26
|
const fs_1 = __importDefault(require("fs"));
|
|
24
27
|
const yaml_1 = __importDefault(require("yaml"));
|
|
25
28
|
const reasoning_1 = require("../agent/reasoning");
|
|
@@ -29,6 +32,7 @@ const config_1 = require("../web3/config");
|
|
|
29
32
|
const tokens_1 = require("../web3/utils/tokens");
|
|
30
33
|
const tracker_1 = require("./tracker");
|
|
31
34
|
const transactionManager_1 = require("../agent/transactionManager");
|
|
35
|
+
const multer_1 = __importDefault(require("multer"));
|
|
32
36
|
const transfer_1 = require("../web3/skills/transfer");
|
|
33
37
|
const swapToken_1 = require("../web3/skills/swapToken");
|
|
34
38
|
const getBalance_1 = require("../web3/skills/getBalance");
|
|
@@ -64,6 +68,9 @@ const xManager_1 = require("../system/skills/xManager");
|
|
|
64
68
|
const notionWorkspace_1 = require("../system/skills/notionWorkspace");
|
|
65
69
|
const audioTranscribe_1 = require("../system/skills/audioTranscribe");
|
|
66
70
|
const summarizeText_1 = require("../system/skills/summarizeText");
|
|
71
|
+
const scheduleTask_1 = require("../system/skills/scheduleTask");
|
|
72
|
+
const cancelTask_1 = require("../system/skills/cancelTask");
|
|
73
|
+
const cronManager_1 = require("../agent/cronManager");
|
|
67
74
|
const updateSecurityPolicy_1 = require("../system/skills/updateSecurityPolicy");
|
|
68
75
|
const writeFile_1 = require("../system/skills/writeFile");
|
|
69
76
|
const generateExcel_1 = require("../system/skills/generateExcel");
|
|
@@ -141,14 +148,11 @@ app.use('/api', (req, res, next) => {
|
|
|
141
148
|
next();
|
|
142
149
|
});
|
|
143
150
|
// Serve Static Dashboard
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
break;
|
|
149
|
-
rootDir = nextDir;
|
|
151
|
+
// __dirname is packages/core/dist/gateway (compiled) OR packages/core/src/gateway (dev)
|
|
152
|
+
let dashboardPath = path_1.default.join(__dirname, '..', '..', '..', 'dashboard', 'dist'); // Dev
|
|
153
|
+
if (!fs_1.default.existsSync(dashboardPath)) {
|
|
154
|
+
dashboardPath = path_1.default.join(__dirname, '..', '..', '..', '..', '..', 'packages', 'dashboard', 'dist'); // Compiled
|
|
150
155
|
}
|
|
151
|
-
const dashboardPath = path_1.default.join(rootDir, 'packages', 'dashboard', 'dist');
|
|
152
156
|
app.use(express_1.default.static(dashboardPath));
|
|
153
157
|
app.get('/', (req, res) => {
|
|
154
158
|
res.sendFile(path_1.default.join(dashboardPath, 'index.html'));
|
|
@@ -159,6 +163,31 @@ app.get('/privacy', (req, res) => {
|
|
|
159
163
|
app.get('/tos', (req, res) => {
|
|
160
164
|
res.send((0, legalGenerator_1.generateTosHtml)());
|
|
161
165
|
});
|
|
166
|
+
const storage = multer_1.default.diskStorage({
|
|
167
|
+
destination: function (req, file, cb) {
|
|
168
|
+
const docsDir = path_1.default.join(os_1.default.homedir(), '.nyxora', 'docs');
|
|
169
|
+
if (!fs_1.default.existsSync(docsDir))
|
|
170
|
+
fs_1.default.mkdirSync(docsDir, { recursive: true });
|
|
171
|
+
cb(null, docsDir);
|
|
172
|
+
},
|
|
173
|
+
filename: function (req, file, cb) {
|
|
174
|
+
const safeName = file.originalname.replace(/[^a-zA-Z0-9.\-_]/g, '_');
|
|
175
|
+
cb(null, `${Date.now()}-${safeName}`);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
const upload = (0, multer_1.default)({ storage });
|
|
179
|
+
app.post('/api/upload', upload.single('file'), (req, res) => {
|
|
180
|
+
try {
|
|
181
|
+
if (!req.file) {
|
|
182
|
+
return res.status(400).json({ error: 'No file uploaded' });
|
|
183
|
+
}
|
|
184
|
+
return res.json({ filePath: req.file.path });
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
console.error('[Upload] Error:', err);
|
|
188
|
+
return res.status(500).json({ error: 'Failed to save file' });
|
|
189
|
+
}
|
|
190
|
+
});
|
|
162
191
|
app.post('/api/upload-google-credentials', (req, res) => {
|
|
163
192
|
try {
|
|
164
193
|
const credentials = req.body.credentials;
|
|
@@ -352,7 +381,9 @@ const systemSkills = [
|
|
|
352
381
|
xManager_1.xManagerToolDefinition,
|
|
353
382
|
notionWorkspace_1.notionWorkspaceToolDefinition,
|
|
354
383
|
audioTranscribe_1.audioTranscribeToolDefinition,
|
|
355
|
-
summarizeText_1.summarizeTextToolDefinition
|
|
384
|
+
summarizeText_1.summarizeTextToolDefinition,
|
|
385
|
+
scheduleTask_1.scheduleTaskDefinition,
|
|
386
|
+
cancelTask_1.cancelTaskDefinition
|
|
356
387
|
];
|
|
357
388
|
app.get('/api/stats', (req, res) => {
|
|
358
389
|
const stats = tracker_1.Tracker.getStats();
|
|
@@ -366,6 +397,12 @@ app.get('/api/stats', (req, res) => {
|
|
|
366
397
|
app.get('/api/logs', (req, res) => {
|
|
367
398
|
res.json(tracker_1.Tracker.getLogs());
|
|
368
399
|
});
|
|
400
|
+
app.get('/api/cron', (req, res) => {
|
|
401
|
+
res.json({
|
|
402
|
+
activeJobs: cronManager_1.cronManager.getActiveJobsCount(),
|
|
403
|
+
jobs: cronManager_1.cronManager.getJobs()
|
|
404
|
+
});
|
|
405
|
+
});
|
|
369
406
|
app.get('/api/skills', (req, res) => {
|
|
370
407
|
const skillsWithStatus = allSkills.map(skill => ({
|
|
371
408
|
...skill,
|
|
@@ -815,6 +852,22 @@ function resetIdleTimer() {
|
|
|
815
852
|
reflection_1.ReflectionEngine.runReflection();
|
|
816
853
|
}, 3 * 60 * 1000); // 3 minutes idle
|
|
817
854
|
}
|
|
855
|
+
app.post('/api/v1/trade', async (req, res) => {
|
|
856
|
+
try {
|
|
857
|
+
const { message, session_id } = req.body;
|
|
858
|
+
if (!message)
|
|
859
|
+
return res.status(400).json({ error: 'Message is required' });
|
|
860
|
+
const traceId = crypto_1.default.randomBytes(8).toString('hex');
|
|
861
|
+
// Asynchronous background execution
|
|
862
|
+
(0, reasoning_1.processUserInput)(message, session_id || traceId).catch(err => {
|
|
863
|
+
console.error(`[TradeAPI] Error:`, err);
|
|
864
|
+
});
|
|
865
|
+
res.status(200).json({ status: 'processing', traceId });
|
|
866
|
+
}
|
|
867
|
+
catch (error) {
|
|
868
|
+
res.status(500).json({ error: error.message });
|
|
869
|
+
}
|
|
870
|
+
});
|
|
818
871
|
app.post('/api/chat', async (req, res) => {
|
|
819
872
|
try {
|
|
820
873
|
const { message, session_id } = req.body;
|
|
@@ -965,6 +1018,8 @@ function startServer() {
|
|
|
965
1018
|
const PORT = Number(process.env.PORT || 3000);
|
|
966
1019
|
const server = app.listen(PORT, '127.0.0.1', () => {
|
|
967
1020
|
console.log(`🤖 Nyxora API Server running on port ${PORT}`);
|
|
1021
|
+
// Initialize WebSocket Manager
|
|
1022
|
+
(0, WebSocketManager_1.initWebSocket)(server);
|
|
968
1023
|
// Start the Telegram bot listener
|
|
969
1024
|
(0, telegram_1.startTelegramBot)();
|
|
970
1025
|
// Start Asynchronous Bridge Watcher
|
|
@@ -276,7 +276,7 @@ Provider: ${config.llm.provider}`;
|
|
|
276
276
|
{ value: 'gitManager', label: 'Git Operations (Commit/Push/Pull)' },
|
|
277
277
|
{ value: 'updateSecurityPolicy', label: 'Update policy.yaml rules', hint: 'safeguard' },
|
|
278
278
|
{ value: 'browseWeb', label: 'Browse & Scrape Webpages' },
|
|
279
|
-
{ value: 'searchWeb', label: 'Smart Web Search (Tavily/Brave)', hint: '
|
|
279
|
+
{ value: 'searchWeb', label: 'Smart Web Search (Tavily/Brave/DuckDuckGo)', hint: 'Optional API Key' },
|
|
280
280
|
{ value: 'googleWorkspace', label: 'Google Workspace (Gmail, Docs, Sheets, Forms)', hint: 'Requires OAuth' },
|
|
281
281
|
{ value: 'notionWorkspace', label: 'Notion Integration' },
|
|
282
282
|
{ value: 'xManager', label: 'X/Twitter Management' },
|
|
@@ -308,15 +308,18 @@ Provider: ${config.llm.provider}`;
|
|
|
308
308
|
options: [
|
|
309
309
|
{ value: 'tavily', label: 'Tavily Search (Built for AI - 1000 free/mo)' },
|
|
310
310
|
{ value: 'brave', label: 'Brave Search (Privacy focused - 2000 free/mo)' },
|
|
311
|
+
{ value: 'duckduckgo', label: 'DuckDuckGo (Free & Built-in)' },
|
|
311
312
|
],
|
|
312
313
|
});
|
|
313
314
|
if ((0, prompts_1.isCancel)(searchProvider))
|
|
314
315
|
return process.exit(0);
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
316
|
+
if (searchProvider !== 'duckduckgo') {
|
|
317
|
+
searchApiKey = (await (0, prompts_1.password)({
|
|
318
|
+
message: `Enter API Key for ${searchProvider} (Get it free at ${searchProvider === 'tavily' ? 'tavily.com' : 'search.brave.com'}):`,
|
|
319
|
+
}));
|
|
320
|
+
if ((0, prompts_1.isCancel)(searchApiKey))
|
|
321
|
+
return process.exit(0);
|
|
322
|
+
}
|
|
320
323
|
}
|
|
321
324
|
const setupTelegram = activeChannels.includes('telegram');
|
|
322
325
|
let telegramToken = '';
|
|
@@ -19,6 +19,9 @@ const executeDefi_1 = require("../web3/skills/executeDefi");
|
|
|
19
19
|
const revokeApprovals_1 = require("../web3/skills/revokeApprovals");
|
|
20
20
|
const formatter_1 = require("../utils/formatter");
|
|
21
21
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
22
|
+
const fs_1 = __importDefault(require("fs"));
|
|
23
|
+
const path_1 = __importDefault(require("path"));
|
|
24
|
+
const os_1 = __importDefault(require("os"));
|
|
22
25
|
let globalBotInstance = null;
|
|
23
26
|
function formatToTelegramHTML(text) {
|
|
24
27
|
if (!text)
|
|
@@ -162,6 +165,46 @@ function startTelegramBot() {
|
|
|
162
165
|
await ctx.reply('❌ Sorry, I encountered an error while processing your message.');
|
|
163
166
|
}
|
|
164
167
|
});
|
|
168
|
+
bot.on('document', async (ctx) => {
|
|
169
|
+
const doc = ctx.message.document;
|
|
170
|
+
const caption = ctx.message.caption || '';
|
|
171
|
+
console.log(`[Telegram] Received document from ${ctx.from?.first_name || 'User'}: ${doc.file_name}`);
|
|
172
|
+
await ctx.sendChatAction('typing');
|
|
173
|
+
try {
|
|
174
|
+
const fileLink = await ctx.telegram.getFileLink(doc.file_id);
|
|
175
|
+
const docsDir = path_1.default.join(os_1.default.homedir(), '.nyxora', 'docs');
|
|
176
|
+
if (!fs_1.default.existsSync(docsDir))
|
|
177
|
+
fs_1.default.mkdirSync(docsDir, { recursive: true });
|
|
178
|
+
const safeName = (doc.file_name || 'telegram_doc').replace(/[^a-zA-Z0-9.\-_]/g, '_');
|
|
179
|
+
const localFilePath = path_1.default.join(docsDir, `${Date.now()}-${safeName}`);
|
|
180
|
+
const res = await fetch(fileLink.toString());
|
|
181
|
+
const buffer = await res.arrayBuffer();
|
|
182
|
+
fs_1.default.writeFileSync(localFilePath, Buffer.from(buffer));
|
|
183
|
+
const prompt = `Tolong analisis dokumen ini: ${localFilePath}\n\n${caption}`;
|
|
184
|
+
let progressMsgId = null;
|
|
185
|
+
const onProgress = async (progressText) => {
|
|
186
|
+
try {
|
|
187
|
+
if (!progressMsgId) {
|
|
188
|
+
const sent = await ctx.reply(`<i>${progressText.replace(/_/g, '')}</i>`, { parse_mode: 'HTML' });
|
|
189
|
+
progressMsgId = sent.message_id;
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
await ctx.telegram.editMessageText(ctx.chat.id, progressMsgId, undefined, `<i>${progressText.replace(/_/g, '')}</i>`, { parse_mode: 'HTML' });
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch (e) { }
|
|
196
|
+
};
|
|
197
|
+
const response = await (0, reasoning_1.processUserInput)(prompt, 'user', onProgress, ctx.chat?.id.toString());
|
|
198
|
+
if (progressMsgId) {
|
|
199
|
+
await ctx.telegram.deleteMessage(ctx.chat.id, progressMsgId).catch(() => { });
|
|
200
|
+
}
|
|
201
|
+
await ctx.reply(formatToTelegramHTML(response), { parse_mode: 'HTML' });
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
console.error('[Telegram] Error processing document:', error);
|
|
205
|
+
await ctx.reply('❌ Sorry, I failed to download or analyze the document.');
|
|
206
|
+
}
|
|
207
|
+
});
|
|
165
208
|
// Handle callbacks
|
|
166
209
|
bot.action(/^approve_(.+)$/, async (ctx) => {
|
|
167
210
|
const txId = ctx.match[1];
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.Tracker = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const WebSocketManager_1 = require("./WebSocketManager");
|
|
9
|
+
const paths_1 = require("../config/paths");
|
|
4
10
|
const stats = {
|
|
5
11
|
cost: 0,
|
|
6
12
|
tokens: 0,
|
|
@@ -9,6 +15,55 @@ const stats = {
|
|
|
9
15
|
const eventLogs = [];
|
|
10
16
|
const gatewayLogs = [];
|
|
11
17
|
const MAX_LOGS = 100;
|
|
18
|
+
let trackerFile = '';
|
|
19
|
+
try {
|
|
20
|
+
trackerFile = (0, paths_1.getPath)('tracker.json');
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
// Fallback
|
|
24
|
+
}
|
|
25
|
+
function loadState() {
|
|
26
|
+
if (!trackerFile)
|
|
27
|
+
return;
|
|
28
|
+
try {
|
|
29
|
+
if (fs_1.default.existsSync(trackerFile)) {
|
|
30
|
+
const data = JSON.parse(fs_1.default.readFileSync(trackerFile, 'utf8'));
|
|
31
|
+
if (data.stats)
|
|
32
|
+
Object.assign(stats, data.stats);
|
|
33
|
+
if (data.eventLogs && Array.isArray(data.eventLogs)) {
|
|
34
|
+
eventLogs.splice(0, eventLogs.length, ...data.eventLogs);
|
|
35
|
+
}
|
|
36
|
+
if (data.gatewayLogs && Array.isArray(data.gatewayLogs)) {
|
|
37
|
+
gatewayLogs.splice(0, gatewayLogs.length, ...data.gatewayLogs);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (e) { }
|
|
42
|
+
}
|
|
43
|
+
let savePending = false;
|
|
44
|
+
function saveState() {
|
|
45
|
+
if (!trackerFile)
|
|
46
|
+
return;
|
|
47
|
+
if (savePending)
|
|
48
|
+
return;
|
|
49
|
+
savePending = true;
|
|
50
|
+
setTimeout(() => {
|
|
51
|
+
flushState();
|
|
52
|
+
savePending = false;
|
|
53
|
+
}, 1000);
|
|
54
|
+
}
|
|
55
|
+
function flushState() {
|
|
56
|
+
if (!trackerFile)
|
|
57
|
+
return;
|
|
58
|
+
try {
|
|
59
|
+
fs_1.default.writeFileSync(trackerFile, JSON.stringify({ stats, eventLogs, gatewayLogs }));
|
|
60
|
+
}
|
|
61
|
+
catch (e) { }
|
|
62
|
+
}
|
|
63
|
+
process.on('exit', flushState);
|
|
64
|
+
process.on('SIGTERM', () => { flushState(); process.exit(0); });
|
|
65
|
+
process.on('SIGINT', () => { flushState(); process.exit(0); });
|
|
66
|
+
loadState();
|
|
12
67
|
function formatTime() {
|
|
13
68
|
const now = new Date();
|
|
14
69
|
return now.toTimeString().split(' ')[0]; // Returns HH:MM:SS
|
|
@@ -23,9 +78,11 @@ exports.Tracker = {
|
|
|
23
78
|
else if (provider === 'gemini')
|
|
24
79
|
rate = 0.00001;
|
|
25
80
|
stats.cost += (amount * rate);
|
|
81
|
+
saveState();
|
|
26
82
|
},
|
|
27
83
|
addMessage: () => {
|
|
28
84
|
stats.messages += 1;
|
|
85
|
+
saveState();
|
|
29
86
|
},
|
|
30
87
|
getStats: () => {
|
|
31
88
|
return { ...stats, cost: Number(stats.cost.toFixed(4)) };
|
|
@@ -34,11 +91,17 @@ exports.Tracker = {
|
|
|
34
91
|
eventLogs.unshift({ timestamp: formatTime(), event, meta });
|
|
35
92
|
if (eventLogs.length > MAX_LOGS)
|
|
36
93
|
eventLogs.pop();
|
|
94
|
+
saveState();
|
|
37
95
|
},
|
|
38
96
|
addGatewayLog: (message, meta) => {
|
|
39
97
|
gatewayLogs.unshift({ timestamp: formatTime(), message, meta });
|
|
40
98
|
if (gatewayLogs.length > MAX_LOGS)
|
|
41
99
|
gatewayLogs.pop();
|
|
100
|
+
saveState();
|
|
101
|
+
// Broadcast terminal logs to Dashboard via WebSocket
|
|
102
|
+
if (WebSocketManager_1.wsManager) {
|
|
103
|
+
WebSocketManager_1.wsManager.broadcastAll(`[${formatTime()}] ${message}`, meta?.level || 'info');
|
|
104
|
+
}
|
|
42
105
|
},
|
|
43
106
|
getLogs: () => {
|
|
44
107
|
return {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cancelTaskDefinition = void 0;
|
|
4
|
+
exports.executeCancelTask = executeCancelTask;
|
|
5
|
+
const cronManager_1 = require("../../agent/cronManager");
|
|
6
|
+
exports.cancelTaskDefinition = {
|
|
7
|
+
type: "function",
|
|
8
|
+
function: {
|
|
9
|
+
name: "cancel_task",
|
|
10
|
+
description: "Cancel a scheduled background task (cron job). Use this when the user asks you to stop monitoring or cancel a previously scheduled task.",
|
|
11
|
+
parameters: {
|
|
12
|
+
type: "object",
|
|
13
|
+
properties: {
|
|
14
|
+
jobId: {
|
|
15
|
+
type: "string",
|
|
16
|
+
description: "The unique Job ID of the scheduled task to cancel."
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
required: ["jobId"]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
async function executeCancelTask(args) {
|
|
24
|
+
const { jobId } = args;
|
|
25
|
+
if (!jobId) {
|
|
26
|
+
return "Error: Missing required parameter jobId.";
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const success = cronManager_1.cronManager.removeJob(jobId);
|
|
30
|
+
if (success) {
|
|
31
|
+
return `Success! I have cancelled the scheduled background task with Job ID: ${jobId}.`;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
return `Failed to cancel task. No active task found with Job ID: ${jobId}. You can check active jobs by asking me what tasks are currently running.`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
return `Failed to cancel task: ${error.message}`;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -10,6 +10,11 @@ const path_1 = __importDefault(require("path"));
|
|
|
10
10
|
function editLocalFile(filePath, searchString, replacementString) {
|
|
11
11
|
try {
|
|
12
12
|
const absolutePath = path_1.default.resolve(filePath);
|
|
13
|
+
// Security Firewall: Block modification of core configuration files
|
|
14
|
+
const basename = path_1.default.basename(absolutePath);
|
|
15
|
+
if (['config.yaml', 'rpc_key.yaml', 'policy.yaml'].includes(basename)) {
|
|
16
|
+
return `Error: Access Denied. You are strictly forbidden from modifying core configuration files directly. If you need to update your agent name, use the update_identity tool instead.`;
|
|
17
|
+
}
|
|
13
18
|
if (!fs_1.default.existsSync(absolutePath)) {
|
|
14
19
|
return `Error: File not found at ${absolutePath}`;
|
|
15
20
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.scheduleTaskDefinition = void 0;
|
|
4
|
+
exports.executeScheduleTask = executeScheduleTask;
|
|
5
|
+
const cronManager_1 = require("../../agent/cronManager");
|
|
6
|
+
exports.scheduleTaskDefinition = {
|
|
7
|
+
type: "function",
|
|
8
|
+
function: {
|
|
9
|
+
name: "schedule_task",
|
|
10
|
+
description: "Schedule a recurring background task for the AI to execute automatically using a cron expression. Use this when the user asks you to remind them or monitor something periodically (e.g. 'check price every hour', 'monitor my wallet every 5 minutes'). The AI will execute the provided prompt at the scheduled interval and send the result via Telegram notification.",
|
|
11
|
+
parameters: {
|
|
12
|
+
type: "object",
|
|
13
|
+
properties: {
|
|
14
|
+
cronExpression: {
|
|
15
|
+
type: "string",
|
|
16
|
+
description: "A standard 5-field cron expression (minute hour day month day-of-week). Examples: '*/5 * * * *' (every 5 mins), '0 * * * *' (every hour), '0 8 * * *' (every day at 8 AM)."
|
|
17
|
+
},
|
|
18
|
+
prompt: {
|
|
19
|
+
type: "string",
|
|
20
|
+
description: "The prompt/command that the AI should execute when the cron triggers. E.g., 'What is the current price of Ethereum?'"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
required: ["cronExpression", "prompt"]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
async function executeScheduleTask(args) {
|
|
28
|
+
const { cronExpression, prompt } = args;
|
|
29
|
+
if (!cronExpression || !prompt) {
|
|
30
|
+
return "Error: Missing required parameters cronExpression or prompt.";
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const jobId = cronManager_1.cronManager.addJob(cronExpression, prompt);
|
|
34
|
+
return `Success! I have scheduled the background task.\nJob ID: ${jobId}\nSchedule: ${cronExpression}\nPrompt to execute: "${prompt}"\n\nYou will receive a notification via Telegram every time this task completes.`;
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
return `Failed to schedule task: ${error.message}. Please ensure the cron expression is valid.`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.searchWebToolDefinition = void 0;
|
|
4
4
|
exports.searchWeb = searchWeb;
|
|
5
5
|
const parser_1 = require("../../config/parser");
|
|
6
|
+
const duck_duck_scrape_1 = require("duck-duck-scrape");
|
|
6
7
|
const SEARXNG_INSTANCES = [
|
|
7
8
|
'https://search.mdosch.de',
|
|
8
9
|
'https://searx.tiekoetter.com',
|
|
@@ -79,6 +80,25 @@ async function searchSearxng(query, depth = 1) {
|
|
|
79
80
|
}
|
|
80
81
|
throw new Error('[SearXNG Error] All decentralized instances failed.');
|
|
81
82
|
}
|
|
83
|
+
async function searchDuckDuckGo(query, depth = 1) {
|
|
84
|
+
try {
|
|
85
|
+
const searchResults = await (0, duck_duck_scrape_1.search)(query, {
|
|
86
|
+
safeSearch: duck_duck_scrape_1.SafeSearchType.MODERATE
|
|
87
|
+
});
|
|
88
|
+
if (!searchResults.noResults && searchResults.results.length > 0) {
|
|
89
|
+
const maxResults = depth > 1 ? 15 : 8;
|
|
90
|
+
return searchResults.results.slice(0, maxResults).map(r => ({
|
|
91
|
+
title: r.title,
|
|
92
|
+
url: r.url,
|
|
93
|
+
content: r.description || r.title
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
throw new Error(`[DuckDuckGo Error] Failed to scrape: ${e.message}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
82
102
|
const searchCache = new Map();
|
|
83
103
|
async function searchWeb(query, depth = 1) {
|
|
84
104
|
// Auto-inject current year for time-sensitive queries
|
|
@@ -119,13 +139,25 @@ async function searchWeb(query, depth = 1) {
|
|
|
119
139
|
results = await searchBrave(finalQuery, creds.brave_key, depth);
|
|
120
140
|
}
|
|
121
141
|
catch (e2) {
|
|
122
|
-
console.warn('[WebSearch] Backup provider (Brave) failed. Falling back to
|
|
123
|
-
|
|
142
|
+
console.warn('[WebSearch] Backup provider (Brave) failed. Falling back to DuckDuckGo (L3)...');
|
|
143
|
+
try {
|
|
144
|
+
results = await searchDuckDuckGo(finalQuery, depth);
|
|
145
|
+
}
|
|
146
|
+
catch (e3) {
|
|
147
|
+
console.warn('[WebSearch] DuckDuckGo failed. Falling back to SearXNG Mesh...');
|
|
148
|
+
results = await searchSearxng(finalQuery, depth);
|
|
149
|
+
}
|
|
124
150
|
}
|
|
125
151
|
}
|
|
126
152
|
else {
|
|
127
|
-
console.warn('[WebSearch] No backup provider found. Falling back to
|
|
128
|
-
|
|
153
|
+
console.warn('[WebSearch] No backup premium provider found. Falling back to DuckDuckGo (L3)...');
|
|
154
|
+
try {
|
|
155
|
+
results = await searchDuckDuckGo(finalQuery, depth);
|
|
156
|
+
}
|
|
157
|
+
catch (e3) {
|
|
158
|
+
console.warn('[WebSearch] DuckDuckGo failed. Falling back to SearXNG Mesh...');
|
|
159
|
+
results = await searchSearxng(finalQuery, depth);
|
|
160
|
+
}
|
|
129
161
|
}
|
|
130
162
|
}
|
|
131
163
|
else {
|
|
@@ -145,13 +177,25 @@ async function searchWeb(query, depth = 1) {
|
|
|
145
177
|
results = await searchTavily(finalQuery, creds.tavily_key, depth);
|
|
146
178
|
}
|
|
147
179
|
catch (e2) {
|
|
148
|
-
console.warn('[WebSearch] Backup provider (Tavily) failed. Falling back to
|
|
149
|
-
|
|
180
|
+
console.warn('[WebSearch] Backup provider (Tavily) failed. Falling back to DuckDuckGo (L3)...');
|
|
181
|
+
try {
|
|
182
|
+
results = await searchDuckDuckGo(finalQuery, depth);
|
|
183
|
+
}
|
|
184
|
+
catch (e3) {
|
|
185
|
+
console.warn('[WebSearch] DuckDuckGo failed. Falling back to SearXNG Mesh...');
|
|
186
|
+
results = await searchSearxng(finalQuery, depth);
|
|
187
|
+
}
|
|
150
188
|
}
|
|
151
189
|
}
|
|
152
190
|
else {
|
|
153
|
-
console.warn('[WebSearch] No backup provider found. Falling back to
|
|
154
|
-
|
|
191
|
+
console.warn('[WebSearch] No backup premium provider found. Falling back to DuckDuckGo (L3)...');
|
|
192
|
+
try {
|
|
193
|
+
results = await searchDuckDuckGo(finalQuery, depth);
|
|
194
|
+
}
|
|
195
|
+
catch (e3) {
|
|
196
|
+
console.warn('[WebSearch] DuckDuckGo failed. Falling back to SearXNG Mesh...');
|
|
197
|
+
results = await searchSearxng(finalQuery, depth);
|
|
198
|
+
}
|
|
155
199
|
}
|
|
156
200
|
}
|
|
157
201
|
else {
|
|
@@ -159,6 +203,15 @@ async function searchWeb(query, depth = 1) {
|
|
|
159
203
|
}
|
|
160
204
|
}
|
|
161
205
|
}
|
|
206
|
+
else if (provider === 'duckduckgo') {
|
|
207
|
+
try {
|
|
208
|
+
results = await searchDuckDuckGo(finalQuery, depth);
|
|
209
|
+
}
|
|
210
|
+
catch (e) {
|
|
211
|
+
console.warn('[WebSearch] Primary provider (DuckDuckGo) failed. Falling back to SearXNG Mesh...');
|
|
212
|
+
results = await searchSearxng(finalQuery, depth);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
162
215
|
else {
|
|
163
216
|
results = await searchSearxng(finalQuery, depth);
|
|
164
217
|
}
|
|
@@ -10,6 +10,11 @@ const path_1 = __importDefault(require("path"));
|
|
|
10
10
|
function writeLocalFile(filePath, content) {
|
|
11
11
|
try {
|
|
12
12
|
const absolutePath = path_1.default.resolve(filePath);
|
|
13
|
+
// Security Firewall: Block modification of core configuration files
|
|
14
|
+
const basename = path_1.default.basename(absolutePath);
|
|
15
|
+
if (['config.yaml', 'rpc_key.yaml', 'policy.yaml'].includes(basename)) {
|
|
16
|
+
return `Error: Access Denied. You are strictly forbidden from modifying core configuration files directly. If you need to update your agent name, use the update_identity tool instead.`;
|
|
17
|
+
}
|
|
13
18
|
const dir = path_1.default.dirname(absolutePath);
|
|
14
19
|
if (!fs_1.default.existsSync(dir)) {
|
|
15
20
|
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
@@ -7,7 +7,7 @@ exports.getPriceToolDefinition = {
|
|
|
7
7
|
type: "function",
|
|
8
8
|
function: {
|
|
9
9
|
name: "get_price",
|
|
10
|
-
description: "Fetches the current price of a cryptocurrency.
|
|
10
|
+
description: "Fetches the current price of a cryptocurrency.",
|
|
11
11
|
parameters: {
|
|
12
12
|
type: "object",
|
|
13
13
|
properties: {
|