nyxora 26.7.1 → 26.7.2
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/CHANGELOG.md +24 -1
- package/README.md +14 -2
- package/dist/packages/core/src/agent/honchoDaemon.js +91 -0
- package/dist/packages/core/src/agent/osAgent.js +82 -60
- package/dist/packages/core/src/agent/reasoning.js +25 -14
- package/dist/packages/core/src/agent/updateProfile.js +13 -16
- package/dist/packages/core/src/agent/web3Agent.js +82 -62
- package/dist/packages/core/src/cognitive/cognitiveManager.js +52 -0
- package/dist/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +54 -0
- package/dist/packages/core/src/config/parser.js +1 -0
- package/dist/packages/core/src/config/paths.js +14 -4
- package/dist/packages/core/src/gateway/server.js +54 -2
- package/dist/packages/core/src/gateway/telegram.js +3 -104
- package/dist/packages/core/src/memory/episodic.js +47 -6
- package/dist/packages/core/src/memory/promotionEngine.js +4 -1
- package/dist/packages/core/src/plugin/PluginManager.js +18 -3
- package/dist/packages/core/src/plugin/registry.js +1 -0
- package/dist/packages/core/src/system/agentskills.js +184 -0
- package/dist/packages/core/src/system/plugins/SystemCorePlugin.js +6 -1
- package/dist/packages/core/src/system/plugins/SystemExternalPlugin.js +18 -0
- package/dist/packages/core/src/system/plugins/SystemWorkspacePlugin.js +6 -1
- package/dist/packages/core/src/system/plugins/createSkill.js +41 -0
- package/dist/packages/core/src/system/skillExtractor.js +94 -0
- package/dist/packages/core/src/system/skills/createAgentSkill.js +84 -0
- package/dist/packages/core/src/system/skills/createCognitiveSkill.js +53 -0
- package/dist/packages/core/src/system/skills/forgetMemory.js +38 -0
- package/dist/packages/core/src/utils/llmUtils.js +4 -3
- package/dist/packages/core/src/utils/skillManager.js +5 -1
- package/dist/packages/core/src/web3/plugins/Web3DefiPlugin.js +6 -1
- package/dist/packages/core/src/web3/plugins/Web3MarketPlugin.js +239 -0
- package/dist/packages/core/src/web3/plugins/Web3SecurityPlugin.js +4 -4
- package/dist/packages/core/src/web3/skills/bridgeToken.js +9 -1
- package/dist/packages/core/src/web3/skills/checkRegistryStatus.js +1 -1
- package/dist/packages/core/src/web3/skills/confirmPendingTx.js +134 -0
- package/dist/packages/core/src/web3/skills/customTx.js +44 -1
- package/dist/packages/core/src/web3/skills/defiLending.js +42 -2
- package/dist/packages/core/src/web3/skills/getTrendingTokens.js +67 -0
- package/dist/packages/core/src/web3/skills/mintNft.js +42 -1
- package/dist/packages/core/src/web3/skills/provideLiquidity.js +45 -3
- package/dist/packages/core/src/web3/skills/revokeApprovals.js +41 -1
- package/dist/packages/core/src/web3/skills/swapToken.js +18 -2
- package/dist/packages/core/src/web3/skills/transfer.js +46 -1
- package/dist/packages/core/src/web3/skills/yieldVault.js +42 -2
- package/dist/packages/core/src/web3/utils/balanceChecker.js +59 -0
- package/package.json +1 -2
- package/packages/core/package.json +1 -1
- package/packages/core/src/agent/honchoDaemon.ts +96 -0
- package/packages/core/src/agent/osAgent.ts +90 -69
- package/packages/core/src/agent/reasoning.ts +28 -14
- package/packages/core/src/agent/updateProfile.ts +17 -16
- package/packages/core/src/agent/web3Agent.ts +89 -71
- package/packages/core/src/cognitive/cognitiveManager.ts +53 -0
- package/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +41 -0
- package/packages/core/src/cognitive/prompts/software-development/plan.md +15 -0
- package/packages/core/src/cognitive/prompts/software-development/systematic-debugging.md +14 -0
- package/packages/core/src/cognitive/prompts/software-development/test-driven-development.md +14 -0
- package/packages/core/src/config/parser.ts +4 -0
- package/packages/core/src/config/paths.ts +13 -4
- package/packages/core/src/gateway/server.ts +63 -2
- package/packages/core/src/gateway/telegram.ts +3 -95
- package/packages/core/src/memory/episodic.ts +52 -6
- package/packages/core/src/memory/promotionEngine.ts +5 -1
- package/packages/core/src/plugin/PluginManager.ts +21 -3
- package/packages/core/src/plugin/registry.ts +2 -0
- package/packages/core/src/system/agentskills.ts +175 -0
- package/packages/core/src/system/plugins/SystemCorePlugin.ts +6 -1
- package/packages/core/src/system/plugins/SystemExternalPlugin.ts +18 -0
- package/packages/core/src/system/plugins/SystemWorkspacePlugin.ts +6 -1
- package/packages/core/src/system/plugins/createSkill.ts +41 -0
- package/packages/core/src/system/skillExtractor.ts +101 -0
- package/packages/core/src/system/skills/createAgentSkill.ts +85 -0
- package/packages/core/src/system/skills/createCognitiveSkill.ts +50 -0
- package/packages/core/src/system/skills/forgetMemory.ts +34 -0
- package/packages/core/src/utils/llmUtils.ts +4 -3
- package/packages/core/src/utils/skillManager.ts +5 -1
- package/packages/core/src/web3/plugins/Web3DefiPlugin.ts +6 -1
- package/packages/core/src/web3/plugins/Web3MarketPlugin.ts +231 -0
- package/packages/core/src/web3/plugins/Web3SecurityPlugin.ts +4 -4
- package/packages/core/src/web3/skills/bridgeToken.ts +12 -2
- package/packages/core/src/web3/skills/checkRegistryStatus.ts +1 -1
- package/packages/core/src/web3/skills/confirmPendingTx.ts +94 -0
- package/packages/core/src/web3/skills/customTx.ts +13 -1
- package/packages/core/src/web3/skills/defiLending.ts +10 -2
- package/packages/core/src/web3/skills/getTrendingTokens.ts +89 -0
- package/packages/core/src/web3/skills/mintNft.ts +10 -1
- package/packages/core/src/web3/skills/provideLiquidity.ts +12 -3
- package/packages/core/src/web3/skills/revokeApprovals.ts +8 -1
- package/packages/core/src/web3/skills/swapToken.ts +20 -3
- package/packages/core/src/web3/skills/transfer.ts +13 -1
- package/packages/core/src/web3/skills/yieldVault.ts +10 -2
- package/packages/core/src/web3/utils/balanceChecker.ts +68 -0
- package/packages/dashboard/dist/assets/index-CSoNa5cx.css +1 -0
- package/packages/dashboard/dist/assets/index-DbRWEoSr.js +16 -0
- package/packages/dashboard/dist/index.html +2 -2
- package/packages/dashboard/package.json +1 -1
- package/packages/mcp-server/package.json +1 -1
- package/packages/policy/package.json +1 -1
- package/packages/signer/package.json +1 -1
- package/packages/dashboard/dist/assets/index-Djg8yTDk.js +0 -16
- package/packages/dashboard/dist/assets/index-VEis1hNq.css +0 -1
|
@@ -11,10 +11,35 @@ const tracker_1 = require("../gateway/tracker");
|
|
|
11
11
|
const episodic_1 = require("../memory/episodic");
|
|
12
12
|
const skillManager_1 = require("../utils/skillManager");
|
|
13
13
|
const registry_1 = require("../plugin/registry");
|
|
14
|
+
const cognitiveManager_1 = require("../cognitive/cognitiveManager");
|
|
15
|
+
const EXECUTION_DISCIPLINE = `
|
|
16
|
+
<tool_persistence>
|
|
17
|
+
Use tools whenever they can increase the accuracy, completeness, or factual correctness of your response.
|
|
18
|
+
Do NOT stop early if another tool call would materially improve the result.
|
|
19
|
+
Continue using tools until the task is completely finished and verified.
|
|
20
|
+
</tool_persistence>
|
|
21
|
+
|
|
22
|
+
<mandatory_tool_use>
|
|
23
|
+
NEVER answer the following using only your internal memory — ALWAYS use the relevant tool:
|
|
24
|
+
- Arithmetic, math, calculations
|
|
25
|
+
- System State: OS version, RAM, processes
|
|
26
|
+
- File contents, file sizes
|
|
27
|
+
- Real-world current events
|
|
28
|
+
</mandatory_tool_use>
|
|
29
|
+
|
|
30
|
+
<act_dont_ask>
|
|
31
|
+
When a user's request has a clear, standard interpretation, take immediate ACTION instead of asking for clarification.
|
|
32
|
+
</act_dont_ask>
|
|
33
|
+
|
|
34
|
+
<task_completion>
|
|
35
|
+
The deliverable must be a working artifact backed by real tool output — not just a description or a plan of how you would do it.
|
|
36
|
+
NEVER fabricate, hallucinate, or forge tool outputs.
|
|
37
|
+
</task_completion>
|
|
38
|
+
`;
|
|
14
39
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
15
40
|
exports.logger = new logger_1.Logger();
|
|
16
41
|
const llmUtils_1 = require("../utils/llmUtils");
|
|
17
|
-
function getSystemPrompt(context = 'web3') {
|
|
42
|
+
function getSystemPrompt(context = 'web3', userInput = '') {
|
|
18
43
|
const config = (0, parser_1.loadConfig)();
|
|
19
44
|
const currentDateTime = new Date().toLocaleString('en-US');
|
|
20
45
|
let basePrompt = `You are Nyxora's Web3 Agent (DeFi Specialist).
|
|
@@ -31,7 +56,11 @@ CRITICAL RULE 4: CONDITIONAL PARALLEL EXECUTION. Parallel tool execution is ONLY
|
|
|
31
56
|
CRITICAL RULE 5: TRANSACTION EXECUTION. For ALL state-changing transactions (swap, bridge, transfer), execute IMMEDIATELY. It will trigger a secure popup.
|
|
32
57
|
CRITICAL RULE 6: NETWORK SAFETY VALIDATION. NEVER GUESS chains or tokens. Ask for confirmation if ambiguous.
|
|
33
58
|
CRITICAL RULE 7: TOOL CONFIDENCE & HALUCINATION PREVENTION. NEVER fabricate blockchain data.
|
|
34
|
-
CRITICAL RULE 8: AMOUNT PRECISION. Use 6 decimal places for precision, or 2 if >$10,000
|
|
59
|
+
CRITICAL RULE 8: AMOUNT PRECISION. Use 6 decimal places for precision, or 2 if >$10,000.
|
|
60
|
+
CRITICAL RULE 9: MARKET CONFIDENCE SCORE. Declare a 'Confidence Score (0-100%)' inside <think>. Warn if < 40%.
|
|
61
|
+
|
|
62
|
+
${EXECUTION_DISCIPLINE}
|
|
63
|
+
`;
|
|
35
64
|
// Inject Episodic Memories
|
|
36
65
|
try {
|
|
37
66
|
const recentMemories = episodic_1.episodicDB.getMemories().slice(0, 10);
|
|
@@ -47,6 +76,11 @@ CRITICAL RULE 8: AMOUNT PRECISION. Use 6 decimal places for precision, or 2 if >
|
|
|
47
76
|
}
|
|
48
77
|
}
|
|
49
78
|
catch { }
|
|
79
|
+
// Inject Active Cognitive Skills
|
|
80
|
+
const activeSOP = cognitiveManager_1.cognitiveManager.loadActiveCognitiveSkills(userInput);
|
|
81
|
+
if (activeSOP) {
|
|
82
|
+
basePrompt += `\n\n[ACTIVE COGNITIVE SKILLS]\n${activeSOP}\n`;
|
|
83
|
+
}
|
|
50
84
|
return basePrompt;
|
|
51
85
|
}
|
|
52
86
|
async function processWeb3Intent(input, role = 'user', onProgress, sessionId) {
|
|
@@ -62,33 +96,48 @@ async function processWeb3Intent(input, role = 'user', onProgress, sessionId) {
|
|
|
62
96
|
const { sanitizeHistoryForLLM } = require('../utils/historySanitizer');
|
|
63
97
|
const sanitizedHistory = sanitizeHistoryForLLM(history, activeTools, config.llm.provider);
|
|
64
98
|
let messages = [
|
|
65
|
-
{ role: 'system', content: getSystemPrompt('web3') },
|
|
99
|
+
{ role: 'system', content: getSystemPrompt('web3', input) },
|
|
66
100
|
...sanitizedHistory
|
|
67
101
|
];
|
|
68
102
|
try {
|
|
69
103
|
const context = 'web3';
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
104
|
+
let turnCount = 0;
|
|
105
|
+
const MAX_TURNS = 10;
|
|
106
|
+
while (turnCount < MAX_TURNS) {
|
|
107
|
+
turnCount++;
|
|
108
|
+
const currentHistory = exports.logger.getHistory(sessionId);
|
|
109
|
+
const sanitizedHistory = sanitizeHistoryForLLM(currentHistory, activeTools, config.llm.provider);
|
|
110
|
+
const messages = [
|
|
111
|
+
{ role: 'system', content: getSystemPrompt('web3', input) },
|
|
112
|
+
...sanitizedHistory
|
|
113
|
+
];
|
|
114
|
+
const response = await (0, llmUtils_1.executeWithRetry)(async (client) => {
|
|
115
|
+
return await client.chat({
|
|
116
|
+
model: config.llm.model,
|
|
117
|
+
temperature: config.llm.temperature,
|
|
118
|
+
messages: messages,
|
|
119
|
+
tools: activeTools
|
|
120
|
+
});
|
|
78
121
|
});
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
122
|
+
const responseMessage = response.message;
|
|
123
|
+
if (turnCount === 1) {
|
|
124
|
+
tracker_1.Tracker.addMessage();
|
|
125
|
+
}
|
|
126
|
+
if (response.usage?.total_tokens) {
|
|
127
|
+
tracker_1.Tracker.addTokens(response.usage.total_tokens, config.llm.provider);
|
|
128
|
+
}
|
|
129
|
+
tracker_1.Tracker.addEvent('llm.response', { provider: config.llm.provider, tool_calls: responseMessage.tool_calls?.length || 0 });
|
|
130
|
+
exports.logger.addEntry({
|
|
131
|
+
role: 'assistant',
|
|
132
|
+
content: responseMessage.content || "",
|
|
133
|
+
tool_calls: responseMessage.tool_calls,
|
|
134
|
+
}, sessionId);
|
|
135
|
+
if (!responseMessage.tool_calls || responseMessage.tool_calls.length === 0) {
|
|
136
|
+
let finalContent = responseMessage.content || "No response generated.";
|
|
137
|
+
finalContent = finalContent.replace(/<(think|thought|thinking|reasoning|analysis|reflection)>[\s\S]*?<\/\1>\n?/gi, '');
|
|
138
|
+
finalContent = finalContent.trim();
|
|
139
|
+
return finalContent;
|
|
140
|
+
}
|
|
92
141
|
let canFastReturnAll = true;
|
|
93
142
|
let accumulatedResults = [];
|
|
94
143
|
// Enabled fastReturnTools to eliminate 2nd LLM latency for transaction popups
|
|
@@ -106,7 +155,11 @@ async function processWeb3Intent(input, role = 'user', onProgress, sessionId) {
|
|
|
106
155
|
if (onProgress)
|
|
107
156
|
onProgress(`_⚡ Running tool: ${toolName}..._`);
|
|
108
157
|
try {
|
|
109
|
-
|
|
158
|
+
let argStr = toolCall.function.arguments;
|
|
159
|
+
if (argStr && !argStr.trim().endsWith('}')) {
|
|
160
|
+
argStr += '}';
|
|
161
|
+
}
|
|
162
|
+
args = JSON.parse(argStr);
|
|
110
163
|
}
|
|
111
164
|
catch (parseError) {
|
|
112
165
|
console.error(picocolors_1.default.red(`[LLM Validation Error] Invalid JSON arguments for ${toolName}: ${parseError.message}`));
|
|
@@ -166,44 +219,11 @@ async function processWeb3Intent(input, role = 'user', onProgress, sessionId) {
|
|
|
166
219
|
exports.logger.addEntry({ role: 'assistant', content: finalContent }, sessionId);
|
|
167
220
|
return finalContent;
|
|
168
221
|
}
|
|
169
|
-
//
|
|
170
|
-
const secondSanitized = sanitizeHistoryForLLM(exports.logger.getHistory(sessionId), activeTools, config.llm.provider);
|
|
171
|
-
const secondMessages = [
|
|
172
|
-
{ role: 'system', content: getSystemPrompt('web3') },
|
|
173
|
-
...secondSanitized
|
|
174
|
-
];
|
|
175
|
-
const secondResponse = await (0, llmUtils_1.executeWithRetry)(async (client) => {
|
|
176
|
-
return await client.chat({
|
|
177
|
-
model: config.llm.model,
|
|
178
|
-
messages: secondMessages,
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
if (secondResponse.usage?.total_tokens) {
|
|
182
|
-
tracker_1.Tracker.addTokens(secondResponse.usage.total_tokens, config.llm.provider);
|
|
183
|
-
}
|
|
184
|
-
tracker_1.Tracker.addEvent('llm.final_response', { provider: config.llm.provider });
|
|
185
|
-
let finalContent = secondResponse.message.content || "";
|
|
186
|
-
// Clean up orphaned <think> blocks that forgot to output </think>
|
|
187
|
-
finalContent = finalContent.replace(/<thought>[\s\S]*?<\/thought>\n?/gi, '');
|
|
188
|
-
finalContent = finalContent.replace(/<think>[\s\S]*?<\/think>\n?/gi, '');
|
|
189
|
-
if (finalContent.includes('<think>')) {
|
|
190
|
-
finalContent = finalContent.replace(/<think>[\s\S]*?\n\n/i, '');
|
|
191
|
-
finalContent = finalContent.replace(/<think>[\s\S]*$/i, '');
|
|
192
|
-
}
|
|
193
|
-
finalContent = finalContent.trim();
|
|
194
|
-
exports.logger.addEntry({ role: 'assistant', content: finalContent }, sessionId);
|
|
195
|
-
return finalContent;
|
|
196
|
-
}
|
|
197
|
-
let finalContent = responseMessage.content || "No response generated.";
|
|
198
|
-
// Clean up orphaned <think> blocks that forgot to output </think>
|
|
199
|
-
finalContent = finalContent.replace(/<thought>[\s\S]*?<\/thought>\n?/gi, '');
|
|
200
|
-
finalContent = finalContent.replace(/<think>[\s\S]*?<\/think>\n?/gi, '');
|
|
201
|
-
if (finalContent.includes('<think>')) {
|
|
202
|
-
finalContent = finalContent.replace(/<think>[\s\S]*?\n\n/i, '');
|
|
203
|
-
finalContent = finalContent.replace(/<think>[\s\S]*$/i, '');
|
|
222
|
+
// Loop continues, sending tool results in the next turn
|
|
204
223
|
}
|
|
205
|
-
|
|
206
|
-
|
|
224
|
+
const maxTurnMsg = "⚠️ Reached maximum interaction limit (10 turns). Please be more specific.";
|
|
225
|
+
exports.logger.addEntry({ role: 'assistant', content: maxTurnMsg }, sessionId);
|
|
226
|
+
return maxTurnMsg;
|
|
207
227
|
}
|
|
208
228
|
catch (error) {
|
|
209
229
|
console.error("LLM Error:", error);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.cognitiveManager = exports.CognitiveManager = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
class CognitiveManager {
|
|
10
|
+
promptsPath;
|
|
11
|
+
constructor() {
|
|
12
|
+
this.promptsPath = path_1.default.join(__dirname, 'prompts');
|
|
13
|
+
}
|
|
14
|
+
loadActiveCognitiveSkills(intent) {
|
|
15
|
+
const activeSOPs = [];
|
|
16
|
+
const lowerIntent = intent.toLowerCase();
|
|
17
|
+
// Mapping of keywords to SOP paths
|
|
18
|
+
const skillMappings = [
|
|
19
|
+
{
|
|
20
|
+
keywords: ['debug', 'error', 'bug', 'fix', 'crash', 'fail', 'trace'],
|
|
21
|
+
file: 'software-development/systematic-debugging.md'
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
keywords: ['tdd', 'test', 'red green', 'unit test', 'jest', 'mocha'],
|
|
25
|
+
file: 'software-development/test-driven-development.md'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
keywords: ['plan', 'architecture', 'design', 'structure', 'blueprint'],
|
|
29
|
+
file: 'software-development/plan.md'
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
keywords: ['binance', 'spot trading', 'exchange trading', 'cex trading', 'api key'],
|
|
33
|
+
file: 'autonomous/binance-trading-integration.md'
|
|
34
|
+
}
|
|
35
|
+
];
|
|
36
|
+
for (const mapping of skillMappings) {
|
|
37
|
+
if (mapping.keywords.some(kw => lowerIntent.includes(kw))) {
|
|
38
|
+
const fullPath = path_1.default.join(this.promptsPath, mapping.file);
|
|
39
|
+
if (fs_1.default.existsSync(fullPath)) {
|
|
40
|
+
const content = fs_1.default.readFileSync(fullPath, 'utf8');
|
|
41
|
+
activeSOPs.push(`--- COGNITIVE SKILL: ${path_1.default.basename(mapping.file, '.md').toUpperCase()} ---\n${content}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (activeSOPs.length === 0) {
|
|
46
|
+
return '';
|
|
47
|
+
}
|
|
48
|
+
return activeSOPs.join('\n\n');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.CognitiveManager = CognitiveManager;
|
|
52
|
+
exports.cognitiveManager = new CognitiveManager();
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Binance Trading Integration SOP
|
|
2
|
+
|
|
3
|
+
## Tujuan
|
|
4
|
+
Membantu Nyxora menyiapkan alur kerja aman untuk analisis, simulasi, dan eksekusi trading Binance melalui API/plugin/tool yang tersedia atau yang akan dibuat.
|
|
5
|
+
|
|
6
|
+
## Prinsip Keamanan Wajib
|
|
7
|
+
1. Jangan pernah meminta atau menyimpan API Secret secara plaintext di chat.
|
|
8
|
+
2. Jangan pernah mengaktifkan permission withdrawal pada API Binance.
|
|
9
|
+
3. Default mode harus read-only atau paper/simulation kecuali user secara eksplisit meminta eksekusi live.
|
|
10
|
+
4. Semua order live wajib membutuhkan konfirmasi eksplisit user sebelum dieksekusi.
|
|
11
|
+
5. Terapkan batas risiko: max notional per trade, max daily loss, allowed symbols, dan allowed order types.
|
|
12
|
+
6. Validasi registry/status agent sebelum transaksi jika eksekusi melibatkan sistem transaksi.
|
|
13
|
+
|
|
14
|
+
## Data yang Harus Dikumpulkan
|
|
15
|
+
- Tipe market: Spot atau Futures.
|
|
16
|
+
- Mode: read-only, paper trading, atau live trading dengan confirmation.
|
|
17
|
+
- Pair yang diizinkan, contoh BTCUSDT, ETHUSDT.
|
|
18
|
+
- Maksimal nilai per trade.
|
|
19
|
+
- Maksimal kerugian harian.
|
|
20
|
+
- Jenis order yang diizinkan: market, limit, stop-limit, OCO.
|
|
21
|
+
- Preferensi strategi: manual, grid, DCA, breakout, mean reversion, atau signal-based.
|
|
22
|
+
|
|
23
|
+
## Alur Setup Aman
|
|
24
|
+
1. Jelaskan bahwa API key/secret tidak boleh dikirim langsung di chat.
|
|
25
|
+
2. Minta user membuat Binance API key dengan permission minimal.
|
|
26
|
+
3. Pastikan withdrawal permission nonaktif.
|
|
27
|
+
4. Simpan credential hanya melalui secret manager/env file terenkripsi, bukan profile/memory/chat.
|
|
28
|
+
5. Jika belum ada tool Binance, tawarkan membuat plugin/tool integrasi Binance dengan approval user.
|
|
29
|
+
6. Uji koneksi dengan endpoint read-only terlebih dahulu.
|
|
30
|
+
7. Uji paper trading/simulasi order.
|
|
31
|
+
8. Baru aktifkan live trading setelah user menyetujui batas risiko.
|
|
32
|
+
|
|
33
|
+
## Alur Trading
|
|
34
|
+
1. Ambil saldo, pair info, ticker, order book, dan fee.
|
|
35
|
+
2. Validasi pair termasuk whitelist user.
|
|
36
|
+
3. Hitung quantity sesuai step size/min notional Binance.
|
|
37
|
+
4. Buat rencana order berisi: pair, side, type, quantity, estimated price, max cost, fee estimate, risiko, dan alasan.
|
|
38
|
+
5. Minta konfirmasi user untuk live order.
|
|
39
|
+
6. Setelah konfirmasi, kirim order.
|
|
40
|
+
7. Verifikasi status order.
|
|
41
|
+
8. Laporkan hasil eksekusi beserta orderId, filled qty, average price, fee, dan status.
|
|
42
|
+
|
|
43
|
+
## Risk Guardrails
|
|
44
|
+
- Tolak order jika pair tidak masuk whitelist.
|
|
45
|
+
- Tolak order jika nilai melebihi max notional per trade.
|
|
46
|
+
- Tolak order jika daily loss limit tercapai.
|
|
47
|
+
- Tolak futures leverage tinggi kecuali user eksplisit menyetujui dan batas risiko jelas.
|
|
48
|
+
- Jangan melakukan revenge trading atau trading beruntun tanpa instruksi.
|
|
49
|
+
|
|
50
|
+
## Format Jawaban ke User
|
|
51
|
+
Gunakan bahasa Indonesia. Ringkas, jelas, dan actionable. Untuk order live, tampilkan ringkasan order dan minta konfirmasi eksplisit sebelum eksekusi.
|
|
52
|
+
|
|
53
|
+
## Disclaimer
|
|
54
|
+
Selalu tekankan bahwa analisis/trading bukan nasihat keuangan dan user bertanggung jawab atas keputusan akhir.
|
|
@@ -25,10 +25,13 @@ function getPath(filename) {
|
|
|
25
25
|
// Determine subdirectory based on filename
|
|
26
26
|
let subDir = '';
|
|
27
27
|
const lowerFile = filename.toLowerCase();
|
|
28
|
-
if (
|
|
28
|
+
if (filename === 'skills' || lowerFile.startsWith('skills/')) {
|
|
29
|
+
subDir = 'skills';
|
|
30
|
+
}
|
|
31
|
+
else if (lowerFile.endsWith('.db') || lowerFile.endsWith('.db-wal') || lowerFile.endsWith('.db-shm') || (lowerFile.endsWith('.json') && lowerFile.includes('memory')) || lowerFile.endsWith('.md') || lowerFile.includes('orders')) {
|
|
29
32
|
subDir = 'data';
|
|
30
33
|
}
|
|
31
|
-
else if (lowerFile.endsWith('.yaml') || lowerFile.includes('config') || lowerFile.includes('
|
|
34
|
+
else if (lowerFile.endsWith('.yaml') || lowerFile.includes('config') || lowerFile.includes('whitelist') || lowerFile.includes('tokens')) {
|
|
32
35
|
subDir = 'config';
|
|
33
36
|
}
|
|
34
37
|
else if (lowerFile.endsWith('.token') || lowerFile.includes('vault') || lowerFile.includes('credentials')) {
|
|
@@ -39,10 +42,17 @@ function getPath(filename) {
|
|
|
39
42
|
}
|
|
40
43
|
const targetDir = path_1.default.join(baseDir, subDir);
|
|
41
44
|
ensureDir(targetDir);
|
|
42
|
-
|
|
45
|
+
let fullPath = path_1.default.join(targetDir, filename);
|
|
46
|
+
// Prevent duplicating the subdirectory name if the filename already includes it
|
|
47
|
+
if (filename === subDir) {
|
|
48
|
+
fullPath = targetDir;
|
|
49
|
+
}
|
|
50
|
+
else if (filename.startsWith(subDir + '/') || filename.startsWith(subDir + '\\')) {
|
|
51
|
+
fullPath = path_1.default.join(baseDir, filename);
|
|
52
|
+
}
|
|
43
53
|
// AUTO-MIGRATION: If file exists in root but not in subdir, move it
|
|
44
54
|
const oldRootPath = path_1.default.join(baseDir, filename);
|
|
45
|
-
if (subDir !== '') {
|
|
55
|
+
if (subDir !== '' && fullPath !== oldRootPath) {
|
|
46
56
|
if (fs_1.default.existsSync(oldRootPath) && !fs_1.default.existsSync(fullPath)) {
|
|
47
57
|
try {
|
|
48
58
|
fs_1.default.renameSync(oldRootPath, fullPath);
|
|
@@ -57,8 +57,11 @@ const googleAuthModule_1 = require("./googleAuthModule");
|
|
|
57
57
|
const legalGenerator_1 = require("./legalGenerator");
|
|
58
58
|
const episodic_1 = require("../memory/episodic");
|
|
59
59
|
const reflection_1 = require("../memory/reflection");
|
|
60
|
+
const honchoDaemon_1 = require("../agent/honchoDaemon");
|
|
60
61
|
// Initialize Google Auth
|
|
61
62
|
(0, googleAuthModule_1.initGoogleAuth)();
|
|
63
|
+
// Start Background Honcho Daemon
|
|
64
|
+
honchoDaemon_1.honchoDaemon.start();
|
|
62
65
|
// Synchronize all active skills to config.yaml on startup
|
|
63
66
|
(0, skillManager_1.syncAllSkillsToConfig)();
|
|
64
67
|
const util_1 = __importDefault(require("util"));
|
|
@@ -404,6 +407,9 @@ const getWeb3Skills = () => {
|
|
|
404
407
|
.filter(p => p.name.startsWith('Web3'))
|
|
405
408
|
.flatMap(p => p.tools);
|
|
406
409
|
};
|
|
410
|
+
const getExternalSkills = () => {
|
|
411
|
+
return registry_1.pluginManager.agentSkills ? registry_1.pluginManager.agentSkills.getToolSchemas() : [];
|
|
412
|
+
};
|
|
407
413
|
const getSystemSkills = () => {
|
|
408
414
|
return registry_1.pluginManager.getPlugins()
|
|
409
415
|
.filter(p => !p.name.startsWith('Web3'))
|
|
@@ -414,10 +420,12 @@ app.get('/api/stats', (req, res) => {
|
|
|
414
420
|
const dbPath = (0, paths_1.getPath)('memory.db');
|
|
415
421
|
const allSkills = getWeb3Skills();
|
|
416
422
|
const systemSkills = getSystemSkills();
|
|
423
|
+
const externalSkills = getExternalSkills();
|
|
417
424
|
const activeWeb3 = allSkills.filter(s => (0, skillManager_1.isSkillActive)(s.function.name)).length;
|
|
418
425
|
const activeSystem = systemSkills.filter(s => (0, skillManager_1.isSkillActive)(s.function.name)).length;
|
|
419
|
-
const
|
|
420
|
-
const
|
|
426
|
+
const activeExternal = externalSkills.filter(s => (0, skillManager_1.isSkillActive)(s.function.name)).length;
|
|
427
|
+
const totalSkills = allSkills.length + systemSkills.length + externalSkills.length;
|
|
428
|
+
const activeSkills = activeWeb3 + activeSystem + activeExternal;
|
|
421
429
|
res.json({ ...stats, memoryPath: dbPath, totalSkills, activeSkills });
|
|
422
430
|
});
|
|
423
431
|
app.get('/api/logs', (req, res) => {
|
|
@@ -437,6 +445,14 @@ app.get('/api/skills', (req, res) => {
|
|
|
437
445
|
}));
|
|
438
446
|
res.json(skillsWithStatus);
|
|
439
447
|
});
|
|
448
|
+
app.get('/api/skills/external', (req, res) => {
|
|
449
|
+
const externalSkills = getExternalSkills();
|
|
450
|
+
const skillsWithStatus = externalSkills.map(skill => ({
|
|
451
|
+
...skill,
|
|
452
|
+
isActive: (0, skillManager_1.isSkillActive)(skill.function.name)
|
|
453
|
+
}));
|
|
454
|
+
res.json(skillsWithStatus);
|
|
455
|
+
});
|
|
440
456
|
app.get('/api/skills/system', (req, res) => {
|
|
441
457
|
const systemSkills = getSystemSkills();
|
|
442
458
|
const skillsWithStatus = systemSkills.map(skill => ({
|
|
@@ -488,6 +504,42 @@ app.get('/api/portfolio/token-metadata', async (req, res) => {
|
|
|
488
504
|
res.status(500).json({ error: err.message });
|
|
489
505
|
}
|
|
490
506
|
});
|
|
507
|
+
// Dashboard Auth Routes
|
|
508
|
+
app.post('/api/auth', (req, res) => {
|
|
509
|
+
try {
|
|
510
|
+
const config = (0, parser_1.loadConfig)();
|
|
511
|
+
const currentPass = config.security?.dashboard_password || '123456';
|
|
512
|
+
if (req.body?.password === currentPass) {
|
|
513
|
+
res.json({ success: true });
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
res.status(401).json({ error: 'Invalid password' });
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
catch (err) {
|
|
520
|
+
res.status(500).json({ error: err.message });
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
app.post('/api/auth/update', (req, res) => {
|
|
524
|
+
try {
|
|
525
|
+
const { oldPassword, newPassword } = req.body;
|
|
526
|
+
const config = (0, parser_1.loadConfig)();
|
|
527
|
+
const currentPass = config.security?.dashboard_password || '123456';
|
|
528
|
+
if (oldPassword !== currentPass) {
|
|
529
|
+
return res.status(401).json({ error: 'Invalid old password' });
|
|
530
|
+
}
|
|
531
|
+
if (!newPassword || newPassword.length < 4) {
|
|
532
|
+
return res.status(400).json({ error: 'New password must be at least 4 characters' });
|
|
533
|
+
}
|
|
534
|
+
config.security = config.security || {};
|
|
535
|
+
config.security.dashboard_password = newPassword;
|
|
536
|
+
(0, parser_1.saveConfig)(config);
|
|
537
|
+
res.json({ success: true });
|
|
538
|
+
}
|
|
539
|
+
catch (err) {
|
|
540
|
+
res.status(500).json({ error: err.message });
|
|
541
|
+
}
|
|
542
|
+
});
|
|
491
543
|
// Google Workspace Auth Routes
|
|
492
544
|
app.get('/api/auth/google/url', (req, res) => {
|
|
493
545
|
const url = (0, googleAuthModule_1.getAuthUrl)();
|
|
@@ -11,16 +11,6 @@ const runner_1 = require("@grammyjs/runner");
|
|
|
11
11
|
const transformer_throttler_1 = require("@grammyjs/transformer-throttler");
|
|
12
12
|
const reasoning_1 = require("../agent/reasoning");
|
|
13
13
|
const parser_1 = require("../config/parser");
|
|
14
|
-
const transactionManager_1 = require("../agent/transactionManager");
|
|
15
|
-
const transfer_1 = require("../web3/skills/transfer");
|
|
16
|
-
const swapToken_1 = require("../web3/skills/swapToken");
|
|
17
|
-
const bridgeToken_1 = require("../web3/skills/bridgeToken");
|
|
18
|
-
const mintNft_1 = require("../web3/skills/mintNft");
|
|
19
|
-
const customTx_1 = require("../web3/skills/customTx");
|
|
20
|
-
const executeDefi_1 = require("../web3/skills/executeDefi");
|
|
21
|
-
const revokeApprovals_1 = require("../web3/skills/revokeApprovals");
|
|
22
|
-
const checkRegistryStatus_1 = require("../web3/skills/checkRegistryStatus");
|
|
23
|
-
const formatter_1 = require("../utils/formatter");
|
|
24
14
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
25
15
|
const fs_1 = __importDefault(require("fs"));
|
|
26
16
|
const path_1 = __importDefault(require("path"));
|
|
@@ -140,19 +130,7 @@ function startTelegramBot() {
|
|
|
140
130
|
if (progressMsgId) {
|
|
141
131
|
await ctx.api.deleteMessage(ctx.chat.id, progressMsgId).catch(() => { });
|
|
142
132
|
}
|
|
143
|
-
|
|
144
|
-
const recentPendingTxs = pendingTxs.filter((tx) => Date.now() - tx.createdAt < 120000);
|
|
145
|
-
if (recentPendingTxs.length > 0) {
|
|
146
|
-
const keyboard = new grammy_1.InlineKeyboard();
|
|
147
|
-
recentPendingTxs.forEach((tx) => {
|
|
148
|
-
keyboard.text(`✅ Approve ${tx.type}`, `approve_${tx.id}`).text(`❌ Reject`, `reject_${tx.id}`).row();
|
|
149
|
-
});
|
|
150
|
-
await ctx.reply(formatToTelegramHTML(response), {
|
|
151
|
-
parse_mode: 'HTML',
|
|
152
|
-
reply_markup: keyboard
|
|
153
|
-
});
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
133
|
+
// Transactions will now use conversational approval (Zero-Latency text prompts) instead of InlineKeyboards.
|
|
156
134
|
await ctx.reply(formatToTelegramHTML(response), { parse_mode: 'HTML' });
|
|
157
135
|
}
|
|
158
136
|
catch (error) {
|
|
@@ -176,7 +154,7 @@ function startTelegramBot() {
|
|
|
176
154
|
const res = await fetch(fileLink);
|
|
177
155
|
const buffer = await res.arrayBuffer();
|
|
178
156
|
fs_1.default.writeFileSync(localFilePath, Buffer.from(buffer));
|
|
179
|
-
const prompt = `
|
|
157
|
+
const prompt = `Please analyze this document: ${localFilePath}\n\n${caption}`;
|
|
180
158
|
let progressMsgId = null;
|
|
181
159
|
const onProgress = async (progressText) => {
|
|
182
160
|
try {
|
|
@@ -201,86 +179,7 @@ function startTelegramBot() {
|
|
|
201
179
|
await ctx.reply('❌ Sorry, I failed to download or analyze the document.');
|
|
202
180
|
}
|
|
203
181
|
});
|
|
204
|
-
|
|
205
|
-
const txId = ctx.match[1];
|
|
206
|
-
const tx = transactionManager_1.txManager.getTransaction(txId);
|
|
207
|
-
if (!tx || tx.status !== 'pending') {
|
|
208
|
-
await ctx.answerCallbackQuery({ text: 'Transaction not found or already processed.', show_alert: true });
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
await ctx.answerCallbackQuery('Processing transaction...');
|
|
212
|
-
await ctx.reply(`⏳ Processing transaction ${txId}...`);
|
|
213
|
-
await ctx.api.editMessageReplyMarkup(ctx.chat.id, ctx.msg.message_id, { reply_markup: { inline_keyboard: [] } }).catch(() => { });
|
|
214
|
-
try {
|
|
215
|
-
// --- Arbitrum Registry Kill-Switch Interceptor ---
|
|
216
|
-
const registryCheck = await (0, checkRegistryStatus_1.checkRegistryStatus)();
|
|
217
|
-
if (!registryCheck.isActive) {
|
|
218
|
-
transactionManager_1.txManager.updateStatus(txId, 'failed', registryCheck.reason);
|
|
219
|
-
reasoning_1.logger.addEntry({ role: 'assistant', content: `❌ **Security Blocked:** ${registryCheck.reason}` }, `telegram_${ctx.chat?.id}`);
|
|
220
|
-
await ctx.reply(formatToTelegramHTML(`❌ **Security Blocked:** ${registryCheck.reason}`), { parse_mode: 'HTML' });
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
// ------------------------------------------------
|
|
224
|
-
let result = '';
|
|
225
|
-
if (tx.type === 'transfer') {
|
|
226
|
-
result = await (0, transfer_1.executeTransfer)(tx.chainName, tx.details, true);
|
|
227
|
-
}
|
|
228
|
-
else if (tx.type === 'swap') {
|
|
229
|
-
result = await (0, swapToken_1.executeSwap)(tx.chainName, tx.details, true);
|
|
230
|
-
}
|
|
231
|
-
else if (tx.type === 'bridge') {
|
|
232
|
-
result = await (0, bridgeToken_1.executeBridge)(tx.chainName, tx.details, true);
|
|
233
|
-
}
|
|
234
|
-
else if (tx.type === 'mint') {
|
|
235
|
-
result = await (0, mintNft_1.executeMintNft)(tx.chainName, tx.details, true);
|
|
236
|
-
}
|
|
237
|
-
else if (tx.type === 'custom') {
|
|
238
|
-
result = await (0, customTx_1.executeCustomTx)(tx.chainName, tx.details, true);
|
|
239
|
-
}
|
|
240
|
-
else if (tx.type === 'approve') {
|
|
241
|
-
result = await (0, executeDefi_1.executeApprove)(tx.chainName, tx.details);
|
|
242
|
-
}
|
|
243
|
-
else if (tx.type === 'aaveSupply') {
|
|
244
|
-
result = await (0, executeDefi_1.executeAaveSupply)(tx.chainName, tx.details);
|
|
245
|
-
}
|
|
246
|
-
else if (tx.type === 'vaultDeposit') {
|
|
247
|
-
result = await (0, executeDefi_1.executeVaultDeposit)(tx.chainName, tx.details);
|
|
248
|
-
}
|
|
249
|
-
else if (tx.type === 'univ3Mint') {
|
|
250
|
-
result = await (0, executeDefi_1.executeUniv3Mint)(tx.chainName, tx.details);
|
|
251
|
-
}
|
|
252
|
-
else if (tx.type === 'revokeApproval') {
|
|
253
|
-
result = await (0, revokeApprovals_1.executeRevokeApproval)(tx.chainName, tx.details, true);
|
|
254
|
-
}
|
|
255
|
-
else if (tx.type === 'limit_order') {
|
|
256
|
-
const success = reasoning_1.logger.activateLimitOrder(tx.details.orderId);
|
|
257
|
-
if (success) {
|
|
258
|
-
result = `Limit Order ${tx.details.orderId} is now ACTIVE. The Event-Driven Engine is monitoring the market.`;
|
|
259
|
-
}
|
|
260
|
-
else {
|
|
261
|
-
throw new Error(`Failed to activate Limit Order. ID not found in database.`);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
transactionManager_1.txManager.updateStatus(txId, 'executed', result);
|
|
265
|
-
const prettyMsg = (0, formatter_1.formatTransactionSuccess)(tx, result);
|
|
266
|
-
await ctx.reply(formatToTelegramHTML(`✅ **Transaction processed: Success**\n\n${prettyMsg}`), { parse_mode: 'HTML' });
|
|
267
|
-
(0, reasoning_1.processUserInput)(`Transaction ${txId} was APPROVED via Telegram. Result: ${result}`, 'system', undefined, `telegram_${ctx.chat?.id}`).catch(() => { });
|
|
268
|
-
}
|
|
269
|
-
catch (err) {
|
|
270
|
-
transactionManager_1.txManager.updateStatus(txId, 'failed', err.message);
|
|
271
|
-
const prettyError = (0, formatter_1.formatTransactionError)(tx, err.message);
|
|
272
|
-
await ctx.reply(prettyError);
|
|
273
|
-
(0, reasoning_1.processUserInput)(`Transaction ${txId} FAILED via Telegram. Error: ${err.message}`, 'system', undefined, `telegram_${ctx.chat?.id}`).catch(() => { });
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
bot.callbackQuery(/^reject_(.+)$/, async (ctx) => {
|
|
277
|
-
const txId = ctx.match[1];
|
|
278
|
-
transactionManager_1.txManager.updateStatus(txId, 'rejected');
|
|
279
|
-
(0, reasoning_1.processUserInput)(`Transaction ${txId} was REJECTED via Telegram. CRITICAL: DO NOT retry or recreate this transaction. Acknowledge this cancellation to the user and stop.`, 'system', undefined, `telegram_${ctx.chat?.id}`).catch(() => { });
|
|
280
|
-
await ctx.answerCallbackQuery('Transaction cancelled.');
|
|
281
|
-
await ctx.reply(`❌ Transaction cancelled.`);
|
|
282
|
-
await ctx.api.editMessageReplyMarkup(ctx.chat.id, ctx.msg.message_id, { reply_markup: { inline_keyboard: [] } }).catch(() => { });
|
|
283
|
-
});
|
|
182
|
+
// Transaction approval and rejection are now handled conversationally via the LLM and the confirm_pending_tx tool.
|
|
284
183
|
bot.catch((err) => {
|
|
285
184
|
console.error('[Telegram] Grammy error:', err);
|
|
286
185
|
});
|