nyxora 26.7.2 → 26.7.3

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.
Files changed (167) hide show
  1. package/CHANGELOG.md +95 -47
  2. package/README.md +23 -19
  3. package/bin/nyxora.mjs +4 -6
  4. package/dist/launcher.js +44 -8
  5. package/dist/packages/core/src/agent/bridgeWatcher.js +3 -2
  6. package/dist/packages/core/src/agent/cronManager.js +2 -2
  7. package/dist/packages/core/src/agent/llmProvider.js +242 -0
  8. package/dist/packages/core/src/agent/nyxDaemon.js +97 -0
  9. package/dist/packages/core/src/agent/osAgent.js +203 -29
  10. package/dist/packages/core/src/agent/reasoning.js +353 -60
  11. package/dist/packages/core/src/agent/reasoningScratchpad.js +47 -0
  12. package/dist/packages/core/src/agent/transactionManager.js +36 -31
  13. package/dist/packages/core/src/agent/web3Agent.js +263 -37
  14. package/dist/packages/core/src/cognitive/cognitiveManager.js +63 -10
  15. package/dist/packages/core/src/config/parser.js +10 -4
  16. package/dist/packages/core/src/gateway/chat.js +56 -13
  17. package/dist/packages/core/src/gateway/cli.js +3 -0
  18. package/dist/packages/core/src/gateway/discordAdapter.js +81 -0
  19. package/dist/packages/core/src/gateway/server.js +58 -9
  20. package/dist/packages/core/src/gateway/setup-ml.js +64 -0
  21. package/dist/packages/core/src/gateway/setup.js +39 -3
  22. package/dist/packages/core/src/gateway/telegram.js +120 -24
  23. package/dist/packages/core/src/memory/episodic.js +47 -3
  24. package/dist/packages/core/src/memory/logger.js +120 -2
  25. package/dist/packages/core/src/memory/promotionEngine.js +18 -5
  26. package/dist/packages/core/src/system/agentskills.js +10 -0
  27. package/dist/packages/core/src/system/plugins/GoogleWorkspacePlugin.js +1 -1
  28. package/dist/packages/core/src/system/plugins/SystemCorePlugin.js +1 -1
  29. package/dist/packages/core/src/system/plugins/SystemExternalPlugin.js +1 -1
  30. package/dist/packages/core/src/system/plugins/SystemPluginInstallerPlugin.js +1 -1
  31. package/dist/packages/core/src/system/plugins/SystemSocialPlugin.js +1 -1
  32. package/dist/packages/core/src/system/plugins/SystemWebPlugin.js +1 -1
  33. package/dist/packages/core/src/system/plugins/SystemWorkspacePlugin.js +3 -3
  34. package/dist/packages/core/src/system/plugins/createSkill.js +1 -1
  35. package/dist/packages/core/src/system/skillExtractor.js +16 -5
  36. package/dist/packages/core/src/system/skills/forgetMemory.js +6 -4
  37. package/dist/packages/core/src/system/skills/scheduleTask.js +7 -2
  38. package/dist/packages/core/src/test_mainnet.js +45 -0
  39. package/dist/packages/core/src/utils/contextSummarizer.js +82 -0
  40. package/dist/packages/core/src/utils/skillManager.js +1 -1
  41. package/dist/packages/core/src/utils/streamSimulator.js +85 -0
  42. package/dist/packages/core/src/web3/aggregator/providers/ArbitrumBridgeProvider.js +28 -11
  43. package/dist/packages/core/src/web3/aggregator/providers/OpBridgeProvider.js +41 -27
  44. package/dist/packages/core/src/web3/aggregator/providers/TestnetSwapProvider.js +65 -0
  45. package/dist/packages/core/src/web3/aggregator/routeSelector.js +7 -1
  46. package/dist/packages/core/src/web3/plugins/Web3DefiPlugin.js +1 -1
  47. package/dist/packages/core/src/web3/plugins/Web3MarketPlugin.js +5 -125
  48. package/dist/packages/core/src/web3/plugins/Web3SecurityPlugin.js +1 -1
  49. package/dist/packages/core/src/web3/plugins/Web3WalletPlugin.js +1 -1
  50. package/dist/packages/core/src/web3/skills/bridgeToken.js +19 -4
  51. package/dist/packages/core/src/web3/skills/checkAddress.js +2 -0
  52. package/dist/packages/core/src/web3/skills/checkPortfolio.js +22 -2
  53. package/dist/packages/core/src/web3/skills/checkSecurity.js +2 -0
  54. package/dist/packages/core/src/web3/skills/confirmPendingTx.js +1 -1
  55. package/dist/packages/core/src/web3/skills/createLimitOrder.js +15 -1
  56. package/dist/packages/core/src/web3/skills/customTx.js +3 -0
  57. package/dist/packages/core/src/web3/skills/defiLending.js +2 -0
  58. package/dist/packages/core/src/web3/skills/getBalance.js +2 -0
  59. package/dist/packages/core/src/web3/skills/getPrice.js +134 -27
  60. package/dist/packages/core/src/web3/skills/getTxHistory.js +2 -0
  61. package/dist/packages/core/src/web3/skills/marketAnalysis.js +28 -191
  62. package/dist/packages/core/src/web3/skills/mintNft.js +3 -0
  63. package/dist/packages/core/src/web3/skills/provideLiquidity.js +16 -12
  64. package/dist/packages/core/src/web3/skills/revokeApprovals.js +2 -0
  65. package/dist/packages/core/src/web3/skills/swapToken.js +20 -2
  66. package/dist/packages/core/src/web3/skills/transfer.js +2 -0
  67. package/dist/packages/core/src/web3/skills/yieldVault.js +2 -0
  68. package/dist/packages/core/src/web3/utils/chains.js +19 -0
  69. package/dist/packages/core/src/web3/utils/marketEngine.js +26 -33
  70. package/dist/packages/signer/src/NyxoraSigner.js +181 -0
  71. package/dist/packages/signer/src/index.js +17 -0
  72. package/dist/packages/signer/src/server.js +25 -161
  73. package/launcher.ts +38 -9
  74. package/package.json +6 -2
  75. package/packages/core/package.json +21 -10
  76. package/packages/core/src/agent/bridgeWatcher.ts +3 -2
  77. package/packages/core/src/agent/cronManager.ts +2 -2
  78. package/packages/core/src/agent/llmProvider.ts +219 -0
  79. package/packages/core/src/agent/nyxDaemon.ts +104 -0
  80. package/packages/core/src/agent/osAgent.ts +230 -32
  81. package/packages/core/src/agent/reasoning.ts +376 -64
  82. package/packages/core/src/agent/reasoningScratchpad.ts +45 -0
  83. package/packages/core/src/agent/transactionManager.ts +36 -28
  84. package/packages/core/src/agent/web3Agent.ts +291 -40
  85. package/packages/core/src/cognitive/cognitiveManager.ts +65 -10
  86. package/packages/core/src/cognitive/prompts/web3/market-analysis.md +24 -0
  87. package/packages/core/src/cognitive/prompts/web3/portfolio-review.md +29 -0
  88. package/packages/core/src/cognitive/prompts/web3/risk-assessment.md +28 -0
  89. package/packages/core/src/cognitive/prompts/web3/trade-planning.md +30 -0
  90. package/packages/core/src/config/parser.ts +15 -4
  91. package/packages/core/src/gateway/chat.ts +57 -15
  92. package/packages/core/src/gateway/cli.ts +4 -0
  93. package/packages/core/src/gateway/discordAdapter.ts +87 -0
  94. package/packages/core/src/gateway/server.ts +66 -10
  95. package/packages/core/src/gateway/setup-ml.ts +68 -0
  96. package/packages/core/src/gateway/setup.ts +41 -3
  97. package/packages/core/src/gateway/telegram.ts +138 -27
  98. package/packages/core/src/memory/episodic.ts +64 -3
  99. package/packages/core/src/memory/logger.ts +142 -2
  100. package/packages/core/src/memory/promotionEngine.ts +19 -5
  101. package/packages/core/src/system/agentskills.ts +10 -0
  102. package/packages/core/src/system/plugins/GoogleWorkspacePlugin.ts +1 -1
  103. package/packages/core/src/system/plugins/SystemCorePlugin.ts +1 -1
  104. package/packages/core/src/system/plugins/SystemExternalPlugin.ts +1 -1
  105. package/packages/core/src/system/plugins/SystemPluginInstallerPlugin.ts +1 -1
  106. package/packages/core/src/system/plugins/SystemSocialPlugin.ts +1 -1
  107. package/packages/core/src/system/plugins/SystemWebPlugin.ts +1 -1
  108. package/packages/core/src/system/plugins/SystemWorkspacePlugin.ts +3 -3
  109. package/packages/core/src/system/plugins/createSkill.ts +1 -1
  110. package/packages/core/src/system/skillExtractor.ts +16 -5
  111. package/packages/core/src/system/skills/forgetMemory.ts +7 -4
  112. package/packages/core/src/system/skills/scheduleTask.ts +7 -2
  113. package/packages/core/src/utils/contextSummarizer.ts +100 -0
  114. package/packages/core/src/utils/skillManager.ts +1 -1
  115. package/packages/core/src/utils/streamSimulator.ts +88 -0
  116. package/packages/core/src/web3/aggregator/providers/ArbitrumBridgeProvider.ts +30 -11
  117. package/packages/core/src/web3/aggregator/providers/OpBridgeProvider.ts +43 -29
  118. package/packages/core/src/web3/aggregator/routeSelector.ts +6 -1
  119. package/packages/core/src/web3/plugins/Web3DefiPlugin.ts +1 -1
  120. package/packages/core/src/web3/plugins/Web3MarketPlugin.ts +6 -125
  121. package/packages/core/src/web3/plugins/Web3SecurityPlugin.ts +1 -1
  122. package/packages/core/src/web3/plugins/Web3WalletPlugin.ts +1 -1
  123. package/packages/core/src/web3/skills/bridgeToken.ts +21 -7
  124. package/packages/core/src/web3/skills/checkAddress.ts +2 -0
  125. package/packages/core/src/web3/skills/checkPortfolio.ts +23 -2
  126. package/packages/core/src/web3/skills/checkSecurity.ts +2 -0
  127. package/packages/core/src/web3/skills/confirmPendingTx.ts +1 -1
  128. package/packages/core/src/web3/skills/createLimitOrder.ts +17 -2
  129. package/packages/core/src/web3/skills/customTx.ts +3 -0
  130. package/packages/core/src/web3/skills/defiLending.ts +2 -0
  131. package/packages/core/src/web3/skills/getBalance.ts +2 -0
  132. package/packages/core/src/web3/skills/getPrice.ts +134 -30
  133. package/packages/core/src/web3/skills/getTxHistory.ts +2 -0
  134. package/packages/core/src/web3/skills/marketAnalysis.ts +45 -188
  135. package/packages/core/src/web3/skills/mintNft.ts +3 -0
  136. package/packages/core/src/web3/skills/provideLiquidity.ts +16 -10
  137. package/packages/core/src/web3/skills/revokeApprovals.ts +2 -0
  138. package/packages/core/src/web3/skills/swapToken.ts +20 -3
  139. package/packages/core/src/web3/skills/transfer.ts +2 -0
  140. package/packages/core/src/web3/skills/yieldVault.ts +2 -0
  141. package/packages/core/src/web3/utils/chains.ts +12 -0
  142. package/packages/core/src/web3/utils/marketEngine.ts +27 -33
  143. package/packages/dashboard/dist/assets/index-BTfp141V.js +18 -0
  144. package/packages/dashboard/dist/assets/index-DK2sTU47.css +1 -0
  145. package/packages/dashboard/dist/index.html +2 -2
  146. package/packages/dashboard/package.json +10 -10
  147. package/packages/mcp-server/dist/server.js +5 -1
  148. package/packages/mcp-server/package.json +6 -6
  149. package/packages/mcp-server/src/server.ts +11 -7
  150. package/packages/policy/package.json +3 -3
  151. package/packages/signer/package.json +16 -6
  152. package/packages/signer/src/NyxoraSigner.ts +161 -0
  153. package/packages/signer/src/index.ts +1 -0
  154. package/packages/signer/src/server.ts +25 -135
  155. package/dist/packages/core/src/agent/honchoDaemon.js +0 -91
  156. package/dist/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +0 -54
  157. package/dist/packages/core/src/gateway/test.js +0 -15
  158. package/dist/packages/core/src/web3/Web3DefiPlugin.js +0 -28
  159. package/dist/packages/core/src/web3/aggregator/aggregatorMainnet.js +0 -260
  160. package/dist/packages/core/src/web3/aggregator/aggregatorTestnet.js +0 -119
  161. package/dist/packages/core/src/web3/skills/nativeOpBridge.js +0 -71
  162. package/packages/core/src/agent/honchoDaemon.ts +0 -96
  163. package/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +0 -41
  164. package/packages/core/src/plugin/registry.test.ts +0 -46
  165. package/packages/core/src/utils/formatter.test.ts +0 -41
  166. package/packages/dashboard/dist/assets/index-CSoNa5cx.css +0 -1
  167. package/packages/dashboard/dist/assets/index-DbRWEoSr.js +0 -16
@@ -24,15 +24,22 @@ function formatToTelegramHTML(text) {
24
24
  .replace(/&/g, '&')
25
25
  .replace(/</g, '&lt;')
26
26
  .replace(/>/g, '&gt;');
27
- html = html.replace(/\*\*(.*?)\*\*/g, '<b>$1</b>');
28
- html = html.replace(/(?<!^|\n)\*(?!\s)(.*?)(?<!\s)\*/g, '<i>$1</i>');
29
- html = html.replace(/_(.*?)_/g, '<i>$1</i>');
30
- html = html.replace(/```([\s\S]*?)```/g, '<pre><code>$1</code></pre>');
31
- html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
32
27
  html = html.replace(/&lt;thought&gt;[\s\S]*?&lt;\/thought&gt;\n?/g, '');
33
28
  html = html.replace(/<thought>[\s\S]*?<\/thought>\n?/g, '');
34
29
  html = html.replace(/&lt;think&gt;[\s\S]*?&lt;\/think&gt;\n?/g, '');
35
30
  html = html.replace(/<think>[\s\S]*?<\/think>\n?/g, '');
31
+ html = html.replace(/```([\s\S]*?)```/g, '<pre><code>$1</code></pre>');
32
+ html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
33
+ html = html.replace(/\*\*(.*?)\*\*/g, (match, p1) => {
34
+ if (p1.includes('<pre>') || p1.includes('<code>'))
35
+ return match;
36
+ return `<b>${p1}</b>`;
37
+ });
38
+ html = html.replace(/(?<!^|\n)\*(?!\s)(.*?)(?<!\s)\*/g, (match, p1) => {
39
+ if (p1.includes('<b>') || p1.includes('</b>') || p1.includes('<pre>') || p1.includes('<code>'))
40
+ return match;
41
+ return `<i>${p1}</i>`;
42
+ });
36
43
  const tableRegex = /(?:\|.*\|(?:\n|$))+/g;
37
44
  html = html.replace(tableRegex, (match) => {
38
45
  return `<pre>${match.trim()}</pre>\n`;
@@ -51,6 +58,20 @@ function startTelegramBot() {
51
58
  globalBotInstance = bot;
52
59
  const throttler = (0, transformer_throttler_1.apiThrottler)();
53
60
  bot.api.config.use(throttler);
61
+ bot.api.config.use(async (prev, method, payload, signal) => {
62
+ try {
63
+ return await prev(method, payload, signal);
64
+ }
65
+ catch (err) {
66
+ if (method === 'getUpdates' && err.message?.includes('ETIMEDOUT')) {
67
+ console.log(picocolors_1.default.yellow('[Telegram] API connection lost (Timeout). Retrying automatically...'));
68
+ }
69
+ else if (method === 'getUpdates') {
70
+ console.log(picocolors_1.default.yellow(`[Telegram] Failed to fetch updates: ${err.message}`));
71
+ }
72
+ throw err; // Rethrow so the runner can gracefully backoff and retry
73
+ }
74
+ });
54
75
  const isPaired = !!config.integrations?.telegram?.authorized_chat_id;
55
76
  let generatedPin = '';
56
77
  let pinExpiry = 0;
@@ -103,7 +124,7 @@ function startTelegramBot() {
103
124
  return;
104
125
  });
105
126
  bot.command('clear', async (ctx) => {
106
- reasoning_1.logger.clear(ctx.chat?.id.toString());
127
+ reasoning_1.logger.clear(`telegram_${ctx.chat?.id}`);
107
128
  await ctx.reply("✅ AI memory has been cleared. Let's start a new chat!");
108
129
  });
109
130
  bot.on('message:text', async (ctx) => {
@@ -112,30 +133,103 @@ function startTelegramBot() {
112
133
  return;
113
134
  console.log(`[Telegram] Received from ${ctx.from?.first_name || 'User'}: ${text}`);
114
135
  await ctx.replyWithChatAction('typing');
115
- try {
116
- let progressMsgId = null;
117
- const onProgress = async (progressText) => {
136
+ // No need for a placeholder message anymore! We use ephemeral drafts.
137
+ const draft_id = Math.floor(Math.random() * 100000000) + 1;
138
+ let buffer = '';
139
+ let lastDraftAt = 0;
140
+ let isDrafting = false;
141
+ const THROTTLE_MS = 100; // Native drafts can be streamed incredibly fast
142
+ const onChunk = async (chunk) => {
143
+ buffer += chunk;
144
+ const now = Date.now();
145
+ if (!isDrafting && now - lastDraftAt >= THROTTLE_MS) {
146
+ isDrafting = true;
118
147
  try {
119
- if (!progressMsgId) {
120
- const sent = await ctx.reply(`<i>${progressText.replace(/_/g, '')}</i>`, { parse_mode: 'HTML' });
121
- progressMsgId = sent.message_id;
122
- }
123
- else {
124
- await ctx.api.editMessageText(ctx.chat.id, progressMsgId, `<i>${progressText.replace(/_/g, '')}</i>`, { parse_mode: 'HTML' });
125
- }
148
+ await ctx.api.sendMessageDraft(ctx.chat.id, draft_id, formatToTelegramHTML(buffer), { parse_mode: 'HTML' });
126
149
  }
127
150
  catch { }
128
- };
129
- const response = await (0, reasoning_1.processUserInput)(text, 'user', onProgress, `telegram_${ctx.chat?.id}`);
130
- if (progressMsgId) {
131
- await ctx.api.deleteMessage(ctx.chat.id, progressMsgId).catch(() => { });
151
+ lastDraftAt = Date.now();
152
+ isDrafting = false;
132
153
  }
133
- // Transactions will now use conversational approval (Zero-Latency text prompts) instead of InlineKeyboards.
134
- await ctx.reply(formatToTelegramHTML(response), { parse_mode: 'HTML' });
154
+ };
155
+ const onProgress = async (msg) => {
156
+ if (!isDrafting) {
157
+ isDrafting = true;
158
+ try {
159
+ await ctx.api.sendMessageDraft(ctx.chat.id, draft_id, `<i>${msg.replace(/_/g, '')}</i>`, { parse_mode: 'HTML' });
160
+ }
161
+ catch { }
162
+ isDrafting = false;
163
+ }
164
+ };
165
+ try {
166
+ const response = await (0, reasoning_1.processUserInputStream)(text, onChunk, onProgress, `telegram_${ctx.chat?.id}`);
167
+ // Finalize by sending the permanent message (which replaces the draft)
168
+ let replyMarkup = undefined;
169
+ if (/Reply \*\*Yes\*\*/i.test(response) && /\*\*No\*\* to cancel/i.test(response)) {
170
+ replyMarkup = new grammy_1.InlineKeyboard()
171
+ .text('✅ Approve', 'tx_approve')
172
+ .text('❌ Reject', 'tx_reject');
173
+ }
174
+ await ctx.reply(formatToTelegramHTML(response), { parse_mode: 'HTML', reply_markup: replyMarkup }).catch((e) => {
175
+ console.error("[Telegram] CRITICAL: ctx.reply failed in text handler:", e.message);
176
+ });
135
177
  }
136
178
  catch (error) {
137
179
  console.error('[Telegram] Error processing message:', error);
138
- await ctx.reply('❌ Sorry, I encountered an error while processing your message.');
180
+ await ctx.reply('❌ Sorry, I encountered an error while processing your message.', {}).catch(() => { });
181
+ }
182
+ });
183
+ bot.on('callback_query:data', async (ctx) => {
184
+ const data = ctx.callbackQuery.data;
185
+ if (data === 'tx_approve' || data === 'tx_reject') {
186
+ await ctx.answerCallbackQuery().catch(() => { });
187
+ await ctx.editMessageReplyMarkup(undefined).catch(() => { });
188
+ const simulatedText = data === 'tx_approve' ? 'yes' : 'no';
189
+ console.log(`[Telegram] User clicked ${simulatedText.toUpperCase()} via Inline Keyboard`);
190
+ if (!ctx.chat)
191
+ return;
192
+ await ctx.replyWithChatAction('typing');
193
+ const draft_id = Math.floor(Math.random() * 100000000) + 1;
194
+ let buffer = '';
195
+ let lastDraftAt = 0;
196
+ let isDrafting = false;
197
+ const onChunk = async (chunk) => {
198
+ buffer += chunk;
199
+ const now = Date.now();
200
+ if (!isDrafting && now - lastDraftAt >= 100) {
201
+ isDrafting = true;
202
+ try {
203
+ await ctx.api.sendMessageDraft(ctx.chat.id, draft_id, formatToTelegramHTML(buffer), { parse_mode: 'HTML' });
204
+ }
205
+ catch { }
206
+ lastDraftAt = Date.now();
207
+ isDrafting = false;
208
+ }
209
+ };
210
+ const onProgress = async (msg) => {
211
+ if (!isDrafting) {
212
+ isDrafting = true;
213
+ try {
214
+ await ctx.api.sendMessageDraft(ctx.chat.id, draft_id, `<i>${msg.replace(/_/g, '')}</i>`, { parse_mode: 'HTML' });
215
+ }
216
+ catch { }
217
+ isDrafting = false;
218
+ }
219
+ };
220
+ try {
221
+ const response = await (0, reasoning_1.processUserInputStream)(simulatedText, onChunk, onProgress, `telegram_${ctx.chat.id}`);
222
+ let replyMarkup = undefined;
223
+ if (/Reply \*\*Yes\*\*/i.test(response) && /\*\*No\*\* to cancel/i.test(response)) {
224
+ replyMarkup = new grammy_1.InlineKeyboard().text('✅ Approve', 'tx_approve').text('❌ Reject', 'tx_reject');
225
+ }
226
+ await ctx.reply(formatToTelegramHTML(response), { parse_mode: 'HTML', reply_markup: replyMarkup }).catch((e) => {
227
+ console.error("[Telegram] CRITICAL: ctx.reply failed in callback:", e.message);
228
+ });
229
+ }
230
+ catch (error) {
231
+ await ctx.reply('❌ Sorry, I encountered an error.', {}).catch(() => { });
232
+ }
139
233
  }
140
234
  });
141
235
  bot.on('message:document', async (ctx) => {
@@ -183,7 +277,9 @@ function startTelegramBot() {
183
277
  bot.catch((err) => {
184
278
  console.error('[Telegram] Grammy error:', err);
185
279
  });
186
- runnerInstance = (0, runner_1.run)(bot);
280
+ runnerInstance = (0, runner_1.run)(bot, {
281
+ runner: { silent: true }
282
+ });
187
283
  if (isPaired) {
188
284
  console.log('🤖 Telegram Bot is running and securely listening for your messages...');
189
285
  }
@@ -36,11 +36,17 @@ class EpisodicMemoryDB {
36
36
  CREATE TABLE IF NOT EXISTS user_personas (
37
37
  id INTEGER PRIMARY KEY AUTOINCREMENT,
38
38
  trait TEXT UNIQUE NOT NULL,
39
+ category TEXT DEFAULT 'general',
39
40
  confidence REAL DEFAULT 0.1,
40
41
  source TEXT,
41
42
  lastUpdated DATETIME DEFAULT CURRENT_TIMESTAMP
42
43
  );
43
44
  `);
45
+ // Migration: add category column if missing (for older DBs)
46
+ try {
47
+ this.db.prepare('ALTER TABLE user_personas ADD COLUMN category TEXT DEFAULT \'general\'').run();
48
+ }
49
+ catch { }
44
50
  }
45
51
  addCandidateFact(fact, confidenceScore = 0.5, category = 'general', ruleType = 'observation', keyTopic) {
46
52
  if (keyTopic) {
@@ -93,6 +99,10 @@ class EpisodicMemoryDB {
93
99
  const stmt = this.db.prepare('DELETE FROM episodic_memories');
94
100
  stmt.run();
95
101
  }
102
+ clearAllPersonas() {
103
+ const stmt = this.db.prepare('DELETE FROM user_personas');
104
+ stmt.run();
105
+ }
96
106
  close() {
97
107
  try {
98
108
  this.db.close();
@@ -100,7 +110,11 @@ class EpisodicMemoryDB {
100
110
  catch { }
101
111
  }
102
112
  // --- PERSONA MODELING ---
103
- updatePersonaTrait(trait, confidence = 0.5, source = 'honcho') {
113
+ /**
114
+ * Legacy method: upsert by exact trait string.
115
+ * Kept for backward compatibility but prefer upsertPersonaByCategory.
116
+ */
117
+ updatePersonaTrait(trait, confidence = 0.5, source = 'nyx_daemon') {
104
118
  const existing = this.db.prepare('SELECT id, confidence FROM user_personas WHERE trait = ?').get(trait);
105
119
  if (existing) {
106
120
  const newConfidence = Math.min(1.0, existing.confidence + (confidence * 0.2));
@@ -108,14 +122,44 @@ class EpisodicMemoryDB {
108
122
  stmt.run(newConfidence, source, existing.id);
109
123
  }
110
124
  else {
111
- const stmt = this.db.prepare('INSERT INTO user_personas (trait, confidence, source) VALUES (?, ?, ?)');
112
- stmt.run(trait, confidence, source);
125
+ const stmt = this.db.prepare('INSERT INTO user_personas (trait, category, confidence, source) VALUES (?, ?, ?, ?)');
126
+ stmt.run(trait, 'general', confidence, source);
127
+ }
128
+ }
129
+ /**
130
+ * Category-based upsert: each category (language, tone, trading_style, behavior)
131
+ * has exactly ONE row in user_personas, identified by category.
132
+ * This ensures confidence accumulates correctly across audit cycles
133
+ * instead of creating duplicate rows with slightly different phrasing.
134
+ */
135
+ upsertPersonaByCategory(category, value, confidence = 0.5, source = 'nyx_daemon') {
136
+ if (!value || !value.trim())
137
+ return;
138
+ const existing = this.db.prepare('SELECT id, confidence FROM user_personas WHERE category = ?').get(category);
139
+ if (existing) {
140
+ const newConfidence = Math.min(1.0, existing.confidence + (confidence * 0.2));
141
+ this.db.prepare('UPDATE user_personas SET trait = ?, confidence = ?, source = ?, lastUpdated = CURRENT_TIMESTAMP WHERE id = ?').run(value.trim(), newConfidence, source, existing.id);
142
+ }
143
+ else {
144
+ this.db.prepare('INSERT INTO user_personas (trait, category, confidence, source) VALUES (?, ?, ?, ?)').run(value.trim(), category, confidence, source);
113
145
  }
114
146
  }
115
147
  getPersonas() {
116
148
  const stmt = this.db.prepare('SELECT * FROM user_personas ORDER BY confidence DESC');
117
149
  return stmt.all();
118
150
  }
151
+ /**
152
+ * Get personas filtered by minimum confidence threshold.
153
+ */
154
+ getStrongPersonas(minConfidence = 0.5) {
155
+ const stmt = this.db.prepare('SELECT * FROM user_personas WHERE confidence >= ? ORDER BY confidence DESC');
156
+ return stmt.all(minConfidence);
157
+ }
158
+ deletePersonaByTrait(keyword) {
159
+ const stmt = this.db.prepare('DELETE FROM user_personas WHERE trait LIKE ?');
160
+ const result = stmt.run(`%${keyword}%`);
161
+ return result.changes || 0;
162
+ }
119
163
  }
120
164
  exports.EpisodicMemoryDB = EpisodicMemoryDB;
121
165
  // Singleton instance
@@ -81,6 +81,32 @@ class Logger {
81
81
  custom_rules TEXT,
82
82
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
83
83
  )
84
+ `);
85
+ // V4: Transaction Persistence
86
+ this.db.exec(`
87
+ CREATE TABLE IF NOT EXISTS pending_transactions (
88
+ id TEXT PRIMARY KEY,
89
+ type TEXT NOT NULL,
90
+ chain_name TEXT NOT NULL,
91
+ details TEXT NOT NULL,
92
+ status TEXT NOT NULL,
93
+ result TEXT,
94
+ nonce TEXT,
95
+ created_at INTEGER NOT NULL
96
+ )
97
+ `);
98
+ this.db.exec(`
99
+ CREATE TABLE IF NOT EXISTS pending_withdrawals (
100
+ id TEXT PRIMARY KEY,
101
+ l2_tx_hash TEXT NOT NULL,
102
+ l1_chain TEXT NOT NULL,
103
+ l2_chain TEXT NOT NULL,
104
+ portal_address TEXT NOT NULL,
105
+ user_address TEXT NOT NULL,
106
+ amount TEXT NOT NULL,
107
+ status TEXT NOT NULL,
108
+ created_at INTEGER NOT NULL
109
+ )
84
110
  `);
85
111
  // Ensure session_id exists for older DBs
86
112
  try {
@@ -158,7 +184,7 @@ class Logger {
158
184
  ORDER BY s.timestamp DESC
159
185
  `).all(term, term);
160
186
  }
161
- getHistory(sessionId, limit = 40) {
187
+ getHistory(sessionId, limit = 70) {
162
188
  let rows;
163
189
  // Phase 2: Sliding Window Algorithm (LLM Context Limit)
164
190
  // Fetch only the last X messages, then order them chronologically
@@ -198,13 +224,45 @@ class Logger {
198
224
  return entry;
199
225
  });
200
226
  }
227
+ /**
228
+ * Returns the N most recent messages across ALL sessions (including Telegram, Discord, and NULL sessions).
229
+ * Used by NyxDaemon to analyze conversation history from every channel.
230
+ */
231
+ getRecentMessagesAllSessions(limit = 30) {
232
+ const rows = this.db.prepare(`
233
+ SELECT * FROM (
234
+ SELECT role, content, name, tool_call_id, tool_calls, session_id, id
235
+ FROM messages
236
+ ORDER BY id DESC LIMIT ?
237
+ ) ORDER BY id ASC
238
+ `).all(limit);
239
+ return rows.map((row) => {
240
+ const entry = {
241
+ role: row.role,
242
+ content: row.content,
243
+ };
244
+ if (row.name)
245
+ entry.name = row.name;
246
+ if (row.tool_call_id)
247
+ entry.tool_call_id = row.tool_call_id;
248
+ if (row.tool_calls)
249
+ entry.tool_calls = JSON.parse(row.tool_calls);
250
+ if (row.session_id)
251
+ entry.session_id = row.session_id;
252
+ return entry;
253
+ });
254
+ }
201
255
  addEntry(entry, sessionId) {
202
256
  if (sessionId) {
203
257
  // Auto-create session if it doesn't exist (e.g. for Telegram integration)
204
258
  try {
205
259
  const sessionExists = this.db.prepare('SELECT 1 FROM sessions WHERE id = ?').get(sessionId);
206
260
  if (!sessionExists) {
207
- const title = sessionId.startsWith('telegram_') ? `Telegram Chat` : 'New Session';
261
+ let title = 'New Session';
262
+ if (sessionId.startsWith('telegram_'))
263
+ title = 'Telegram Chat';
264
+ else if (sessionId.startsWith('discord_'))
265
+ title = 'Discord Chat';
208
266
  this.db.prepare('INSERT INTO sessions (id, title) VALUES (?, ?)').run(sessionId, title);
209
267
  }
210
268
  }
@@ -294,6 +352,66 @@ class Logger {
294
352
  const result = this.db.prepare(`UPDATE limit_orders SET status = 'ACTIVE' WHERE id = ?`).run(orderId);
295
353
  return result.changes > 0;
296
354
  }
355
+ // V4: Transaction Persistence Methods
356
+ savePendingTransaction(tx) {
357
+ this.db.prepare(`
358
+ INSERT INTO pending_transactions (id, type, chain_name, details, status, result, nonce, created_at)
359
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
360
+ ON CONFLICT(id) DO UPDATE SET
361
+ status = excluded.status,
362
+ result = excluded.result,
363
+ nonce = excluded.nonce
364
+ `).run(tx.id, tx.type, tx.chainName, JSON.stringify(tx.details), tx.status, tx.result || null, tx.nonce || null, tx.createdAt || Date.now());
365
+ }
366
+ getPendingTransactions() {
367
+ const rows = this.db.prepare(`SELECT * FROM pending_transactions WHERE status = 'pending'`).all();
368
+ return rows.map(r => ({
369
+ id: r.id,
370
+ type: r.type,
371
+ chainName: r.chain_name,
372
+ details: JSON.parse(r.details),
373
+ status: r.status,
374
+ result: r.result,
375
+ nonce: r.nonce,
376
+ createdAt: r.created_at
377
+ }));
378
+ }
379
+ getTransaction(id) {
380
+ const r = this.db.prepare(`SELECT * FROM pending_transactions WHERE id = ?`).get(id);
381
+ if (!r)
382
+ return undefined;
383
+ return {
384
+ id: r.id,
385
+ type: r.type,
386
+ chainName: r.chain_name,
387
+ details: JSON.parse(r.details),
388
+ status: r.status,
389
+ result: r.result,
390
+ nonce: r.nonce,
391
+ createdAt: r.created_at
392
+ };
393
+ }
394
+ savePendingWithdrawal(w) {
395
+ this.db.prepare(`
396
+ INSERT INTO pending_withdrawals (id, l2_tx_hash, l1_chain, l2_chain, portal_address, user_address, amount, status, created_at)
397
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
398
+ ON CONFLICT(id) DO UPDATE SET status = excluded.status
399
+ `).run(w.id, w.l2TxHash, w.l1Chain, w.l2Chain, w.portalAddress, w.userAddress, w.amount, w.status, w.createdAt || Date.now());
400
+ }
401
+ getPendingWithdrawals() {
402
+ const rows = this.db.prepare(`SELECT * FROM pending_withdrawals WHERE status != 'COMPLETED'`).all();
403
+ return rows.map(r => ({
404
+ id: r.id,
405
+ l2TxHash: r.l2_tx_hash,
406
+ l1Chain: r.l1_chain,
407
+ l2Chain: r.l2_chain,
408
+ portalAddress: r.portal_address,
409
+ userAddress: r.user_address,
410
+ amount: r.amount,
411
+ status: r.status,
412
+ createdAt: r.created_at
413
+ }));
414
+ }
297
415
  }
298
416
  exports.Logger = Logger;
299
417
  exports.logger = new Logger();
@@ -38,18 +38,31 @@ class PromotionEngine {
38
38
  // Deduplicate arrays
39
39
  const uniquePermanent = [...new Set(permanentPreferences)];
40
40
  const uniqueRecent = [...new Set(recentObservations)];
41
- // 4. Rewrite user.md (The Golden Profile)
42
- this.rewriteUserProfile(uniquePermanent, uniqueRecent);
41
+ // 4. Fetch Persona Traits
42
+ const personas = episodic_1.episodicDB.getStrongPersonas(0.4);
43
+ const personaStrings = [];
44
+ for (const p of personas) {
45
+ personaStrings.push(`- [${p.category.toUpperCase()}] ${p.trait}`);
46
+ }
47
+ // 5. Rewrite user.md (The Golden Profile)
48
+ this.rewriteUserProfile(uniquePermanent, uniqueRecent, personaStrings);
43
49
  }
44
50
  catch (error) {
45
51
  console.error('[PromotionEngine] Error running promotion engine:', error);
46
52
  }
47
53
  }
48
- static rewriteUserProfile(permanent, recent) {
54
+ static rewriteUserProfile(permanent, recent, personas = []) {
49
55
  const userMdPath = (0, paths_1.getPath)('user.md');
50
56
  let newContent = `Write custom instructions, special rules, user profiles, or the persona you want for Nyxora AI in this file.\n\n`;
51
57
  newContent += `<!-- AUTOMANAGED BY PROMOTION ENGINE. MANUAL EDITS MAY BE OVERWRITTEN -->\n\n`;
52
- newContent += `# Permanent Preferences\n`;
58
+ newContent += `# User Persona & Identity\n`;
59
+ if (personas.length === 0) {
60
+ newContent += `*(No specific persona traits identified yet)*\n`;
61
+ }
62
+ else {
63
+ newContent += personas.join('\n') + '\n';
64
+ }
65
+ newContent += `\n# Permanent Preferences\n`;
53
66
  if (permanent.length === 0) {
54
67
  newContent += `*(No permanent preferences recorded yet)*\n`;
55
68
  }
@@ -64,7 +77,7 @@ class PromotionEngine {
64
77
  newContent += recent.join('\n') + '\n';
65
78
  }
66
79
  fs_1.default.writeFileSync(userMdPath, newContent, 'utf-8');
67
- console.log(`[PromotionEngine] user.md successfully synchronized with Layer 2 Episodic Memory.`);
80
+ console.log(`[PromotionEngine] user.md successfully synchronized with Layer 2 Episodic Memory and Personas.`);
68
81
  }
69
82
  }
70
83
  exports.PromotionEngine = PromotionEngine;
@@ -161,6 +161,16 @@ class AgentSkills {
161
161
  if (!fs_1.default.existsSync(scriptPath)) {
162
162
  throw new Error(`Execution script not found for skill '${name}' at path: ${scriptPath}`);
163
163
  }
164
+ // Automatically load .env for the skill if it exists
165
+ const envPath = path_1.default.join(this.skillsDir, name, '.env');
166
+ if (fs_1.default.existsSync(envPath)) {
167
+ try {
168
+ require('dotenv').config({ path: envPath });
169
+ }
170
+ catch (e) {
171
+ console.warn(`[AgentSkills] Failed to load .env for skill '${name}':`, e);
172
+ }
173
+ }
164
174
  try {
165
175
  // Dynamic import of the TS/JS module
166
176
  const module = await Promise.resolve(`${scriptPath}`).then(s => __importStar(require(s)));
@@ -5,7 +5,7 @@ const googleWorkspace_1 = require("../skills/googleWorkspace");
5
5
  class GoogleWorkspacePlugin {
6
6
  name = 'GoogleWorkspacePlugin';
7
7
  description = 'Google Workspace operations including Gmail, Calendar, Docs, and Sheets.';
8
- version = '1.0.0';
8
+ version = '1.0.1';
9
9
  tools = [
10
10
  googleWorkspace_1.readGmailInboxToolDefinition,
11
11
  googleWorkspace_1.listCalendarEventsToolDefinition,
@@ -10,7 +10,7 @@ const forgetMemory_1 = require("../skills/forgetMemory");
10
10
  class SystemCorePlugin {
11
11
  name = 'SystemCorePlugin';
12
12
  description = 'Core system identity, profile, and task scheduling operations.';
13
- version = '1.0.0';
13
+ version = '1.0.1';
14
14
  tools = [
15
15
  updateProfile_1.updateProfileToolDefinition,
16
16
  updateIdentity_1.updateIdentityToolDefinition,
@@ -5,7 +5,7 @@ const createAgentSkill_1 = require("../skills/createAgentSkill");
5
5
  class SystemExternalPlugin {
6
6
  name = 'SystemExternalPlugin';
7
7
  description = 'Provides tools for creating and managing third-party external agent skills.';
8
- version = '1.0.0';
8
+ version = '1.0.1';
9
9
  tools = [
10
10
  createAgentSkill_1.createAgentSkillToolDefinition
11
11
  ];
@@ -25,7 +25,7 @@ const installPluginDefinition = {
25
25
  class SystemPluginInstallerPlugin {
26
26
  name = 'SystemPluginInstallerPlugin';
27
27
  description = 'Autonomous package manager for installing and auto-healing dynamic plugins.';
28
- version = '1.0.0';
28
+ version = '1.0.1';
29
29
  tools = [installPluginDefinition];
30
30
  handlers = {
31
31
  ['install_plugin']: async (args) => {
@@ -6,7 +6,7 @@ const notionWorkspace_1 = require("../skills/notionWorkspace");
6
6
  class SystemSocialPlugin {
7
7
  name = 'SystemSocialPlugin';
8
8
  description = 'Social media and external workspace operations (Twitter, Notion).';
9
- version = '1.0.0';
9
+ version = '1.0.1';
10
10
  tools = [
11
11
  xManager_1.xManagerToolDefinition,
12
12
  notionWorkspace_1.notionWorkspaceToolDefinition
@@ -9,7 +9,7 @@ const audioTranscribe_1 = require("../skills/audioTranscribe");
9
9
  class SystemWebPlugin {
10
10
  name = 'SystemWebPlugin';
11
11
  description = 'Web browsing, searching, and media analysis operations.';
12
- version = '1.0.0';
12
+ version = '1.0.1';
13
13
  tools = [
14
14
  browseWeb_1.browseWebsiteToolDefinition,
15
15
  searchWeb_1.searchWebToolDefinition,
@@ -11,7 +11,7 @@ const createCognitiveSkill_1 = require("../skills/createCognitiveSkill");
11
11
  class SystemWorkspacePlugin {
12
12
  name = 'SystemWorkspacePlugin';
13
13
  description = 'Local system operations including file management, terminal execution, and Git.';
14
- version = '1.0.0';
14
+ version = '1.0.1';
15
15
  tools = [
16
16
  readFile_1.readLocalFileToolDefinition,
17
17
  writeFile_1.writeLocalFileToolDefinition,
@@ -31,8 +31,8 @@ class SystemWorkspacePlugin {
31
31
  ['edit_local_file']: async (args) => {
32
32
  return await (0, editFile_1.editLocalFile)(args.filePath, args.searchString, args.replacementString);
33
33
  },
34
- ['generate_excel_report']: async (args) => {
35
- return await (0, generateExcel_1.generateExcelFile)(args.data, args.filename);
34
+ ['generate_excel_file']: async (args) => {
35
+ return await (0, generateExcel_1.generateExcelFile)(args.data, args.filePath);
36
36
  },
37
37
  ['run_terminal_command']: async (args) => {
38
38
  return await (0, executeShell_1.runTerminalCommand)(args.command);
@@ -5,7 +5,7 @@ const skillExtractor_1 = require("../skillExtractor");
5
5
  const reasoning_1 = require("../../agent/reasoning");
6
6
  class CreateSkillPlugin {
7
7
  name = 'CreateSkill';
8
- version = '1.0.0';
8
+ version = '1.0.1';
9
9
  description = 'Autonomously extracts and creates skills for Nyxora.';
10
10
  tools = [
11
11
  {
@@ -30,11 +30,22 @@ User Intent / Logic: ${userIntent}
30
30
  Chat Traces (if any):
31
31
  ${historyTraces.join('\n')}
32
32
 
33
- The SKILL.md must contain a YAML frontmatter block with:
34
- - name: ${safeName}
35
- - version: 1.0.0
36
- - description
37
- - parameters (OpenAI function calling schema format)
33
+ The SKILL.md must contain a YAML frontmatter block exactly following this structure:
34
+ ---
35
+ name: ${safeName}
36
+ version: 1.0.0
37
+ description: <Your generated description>
38
+ parameters:
39
+ type: object
40
+ properties:
41
+ param1:
42
+ type: string
43
+ description: ...
44
+ required:
45
+ - param1
46
+ ---
47
+
48
+ CRITICAL: The 'required' array MUST be indented exactly inside the 'parameters' block as shown above. Do NOT put 'required' at the root level of the YAML.
38
49
 
39
50
  Do NOT write anything outside the frontmatter except an optional markdown description below it.
40
51
  Output ONLY the raw SKILL.md content.`;
@@ -23,13 +23,15 @@ exports.forgetMemoryToolDefinition = {
23
23
  };
24
24
  async function forgetMemory(keyword) {
25
25
  try {
26
- const changes = episodic_1.episodicDB.deleteMemoryByFact(keyword);
27
- if (changes > 0) {
26
+ const memoryChanges = episodic_1.episodicDB.deleteMemoryByFact(keyword);
27
+ const personaChanges = episodic_1.episodicDB.deletePersonaByTrait(keyword);
28
+ const totalChanges = memoryChanges + personaChanges;
29
+ if (totalChanges > 0) {
28
30
  await promotionEngine_1.PromotionEngine.runPromotionAndDecay();
29
- return `[Success] Deleted ${changes} memory records containing the keyword '${keyword}'. The user.md profile has been synchronized.`;
31
+ return `[Success] Deleted ${memoryChanges} memory record(s) and ${personaChanges} persona trait(s) containing '${keyword}'. Profile synchronized.`;
30
32
  }
31
33
  else {
32
- return `[Info] No memories found containing the keyword '${keyword}'.`;
34
+ return `[Info] No memories or persona traits found containing the keyword '${keyword}'.`;
33
35
  }
34
36
  }
35
37
  catch (error) {