nyxora 26.7.2 → 26.7.4

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 (192) hide show
  1. package/CHANGELOG.md +112 -47
  2. package/README.md +25 -21
  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 +245 -0
  8. package/dist/packages/core/src/agent/nyxDaemon.js +97 -0
  9. package/dist/packages/core/src/agent/osAgent.js +351 -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/googleAuthModule.js +2 -0
  20. package/dist/packages/core/src/gateway/server.js +58 -9
  21. package/dist/packages/core/src/gateway/setup-ml.js +64 -0
  22. package/dist/packages/core/src/gateway/setup.js +39 -3
  23. package/dist/packages/core/src/gateway/telegram.js +123 -27
  24. package/dist/packages/core/src/memory/episodic.js +58 -3
  25. package/dist/packages/core/src/memory/logger.js +120 -2
  26. package/dist/packages/core/src/memory/promotionEngine.js +18 -5
  27. package/dist/packages/core/src/system/agentskills.js +10 -0
  28. package/dist/packages/core/src/system/plugins/GoogleWorkspacePlugin.js +10 -2
  29. package/dist/packages/core/src/system/plugins/SystemCorePlugin.js +1 -1
  30. package/dist/packages/core/src/system/plugins/SystemExternalPlugin.js +1 -1
  31. package/dist/packages/core/src/system/plugins/SystemPluginInstallerPlugin.js +1 -1
  32. package/dist/packages/core/src/system/plugins/SystemSocialPlugin.js +1 -1
  33. package/dist/packages/core/src/system/plugins/SystemWebPlugin.js +1 -1
  34. package/dist/packages/core/src/system/plugins/SystemWorkspacePlugin.js +3 -3
  35. package/dist/packages/core/src/system/plugins/createSkill.js +1 -1
  36. package/dist/packages/core/src/system/skillExtractor.js +16 -5
  37. package/dist/packages/core/src/system/skills/executeShell.js +31 -4
  38. package/dist/packages/core/src/system/skills/forgetMemory.js +6 -4
  39. package/dist/packages/core/src/system/skills/googleWorkspace.js +106 -1
  40. package/dist/packages/core/src/system/skills/scheduleTask.js +7 -2
  41. package/dist/packages/core/src/system/skills/searchWeb.js +13 -6
  42. package/dist/packages/core/src/test_mainnet.js +45 -0
  43. package/dist/packages/core/src/utils/contextSummarizer.js +82 -0
  44. package/dist/packages/core/src/utils/skillManager.js +1 -1
  45. package/dist/packages/core/src/utils/streamSimulator.js +85 -0
  46. package/dist/packages/core/src/web3/aggregator/providers/ArbitrumBridgeProvider.js +28 -11
  47. package/dist/packages/core/src/web3/aggregator/providers/OpBridgeProvider.js +41 -27
  48. package/dist/packages/core/src/web3/aggregator/providers/TestnetSwapProvider.js +65 -0
  49. package/dist/packages/core/src/web3/aggregator/routeSelector.js +7 -1
  50. package/dist/packages/core/src/web3/plugins/Web3DefiPlugin.js +1 -1
  51. package/dist/packages/core/src/web3/plugins/Web3MarketPlugin.js +5 -125
  52. package/dist/packages/core/src/web3/plugins/Web3SecurityPlugin.js +1 -1
  53. package/dist/packages/core/src/web3/plugins/Web3WalletPlugin.js +1 -1
  54. package/dist/packages/core/src/web3/skills/bridgeToken.js +19 -4
  55. package/dist/packages/core/src/web3/skills/checkAddress.js +2 -0
  56. package/dist/packages/core/src/web3/skills/checkPortfolio.js +22 -2
  57. package/dist/packages/core/src/web3/skills/checkSecurity.js +2 -0
  58. package/dist/packages/core/src/web3/skills/confirmPendingTx.js +1 -1
  59. package/dist/packages/core/src/web3/skills/createLimitOrder.js +15 -1
  60. package/dist/packages/core/src/web3/skills/customTx.js +3 -0
  61. package/dist/packages/core/src/web3/skills/defiLending.js +2 -0
  62. package/dist/packages/core/src/web3/skills/getBalance.js +2 -0
  63. package/dist/packages/core/src/web3/skills/getPrice.js +134 -27
  64. package/dist/packages/core/src/web3/skills/getTxHistory.js +2 -0
  65. package/dist/packages/core/src/web3/skills/marketAnalysis.js +28 -191
  66. package/dist/packages/core/src/web3/skills/mintNft.js +3 -0
  67. package/dist/packages/core/src/web3/skills/provideLiquidity.js +16 -12
  68. package/dist/packages/core/src/web3/skills/revokeApprovals.js +2 -0
  69. package/dist/packages/core/src/web3/skills/swapToken.js +20 -2
  70. package/dist/packages/core/src/web3/skills/transfer.js +2 -0
  71. package/dist/packages/core/src/web3/skills/yieldVault.js +2 -0
  72. package/dist/packages/core/src/web3/utils/chains.js +19 -0
  73. package/dist/packages/core/src/web3/utils/marketEngine.js +26 -33
  74. package/dist/packages/signer/src/NyxoraSigner.js +181 -0
  75. package/dist/packages/signer/src/index.js +17 -0
  76. package/dist/packages/signer/src/server.js +25 -161
  77. package/launcher.ts +38 -9
  78. package/package.json +8 -3
  79. package/packages/core/package.json +21 -10
  80. package/packages/core/src/agent/bridgeWatcher.ts +3 -2
  81. package/packages/core/src/agent/cronManager.ts +2 -2
  82. package/packages/core/src/agent/llmProvider.ts +221 -0
  83. package/packages/core/src/agent/nyxDaemon.ts +104 -0
  84. package/packages/core/src/agent/osAgent.ts +381 -32
  85. package/packages/core/src/agent/reasoning.ts +376 -64
  86. package/packages/core/src/agent/reasoningScratchpad.ts +45 -0
  87. package/packages/core/src/agent/transactionManager.ts +36 -28
  88. package/packages/core/src/agent/web3Agent.ts +291 -40
  89. package/packages/core/src/cognitive/cognitiveManager.ts +65 -10
  90. package/packages/core/src/cognitive/prompts/web3/market-analysis.md +24 -0
  91. package/packages/core/src/cognitive/prompts/web3/portfolio-review.md +29 -0
  92. package/packages/core/src/cognitive/prompts/web3/risk-assessment.md +28 -0
  93. package/packages/core/src/cognitive/prompts/web3/trade-planning.md +30 -0
  94. package/packages/core/src/config/parser.ts +15 -4
  95. package/packages/core/src/gateway/chat.ts +57 -15
  96. package/packages/core/src/gateway/cli.ts +4 -0
  97. package/packages/core/src/gateway/discordAdapter.ts +87 -0
  98. package/packages/core/src/gateway/googleAuthModule.ts +2 -0
  99. package/packages/core/src/gateway/server.ts +66 -10
  100. package/packages/core/src/gateway/setup-ml.ts +68 -0
  101. package/packages/core/src/gateway/setup.ts +41 -3
  102. package/packages/core/src/gateway/telegram.ts +141 -30
  103. package/packages/core/src/memory/episodic.ts +76 -3
  104. package/packages/core/src/memory/logger.ts +142 -2
  105. package/packages/core/src/memory/promotionEngine.ts +19 -5
  106. package/packages/core/src/system/agentskills.ts +10 -0
  107. package/packages/core/src/system/plugins/GoogleWorkspacePlugin.ts +15 -3
  108. package/packages/core/src/system/plugins/SystemCorePlugin.ts +1 -1
  109. package/packages/core/src/system/plugins/SystemExternalPlugin.ts +1 -1
  110. package/packages/core/src/system/plugins/SystemPluginInstallerPlugin.ts +1 -1
  111. package/packages/core/src/system/plugins/SystemSocialPlugin.ts +1 -1
  112. package/packages/core/src/system/plugins/SystemWebPlugin.ts +1 -1
  113. package/packages/core/src/system/plugins/SystemWorkspacePlugin.ts +3 -3
  114. package/packages/core/src/system/plugins/createSkill.ts +1 -1
  115. package/packages/core/src/system/skillExtractor.ts +16 -5
  116. package/packages/core/src/system/skills/executeShell.ts +38 -7
  117. package/packages/core/src/system/skills/forgetMemory.ts +7 -4
  118. package/packages/core/src/system/skills/googleWorkspace.ts +109 -0
  119. package/packages/core/src/system/skills/scheduleTask.ts +7 -2
  120. package/packages/core/src/system/skills/searchWeb.ts +12 -6
  121. package/packages/core/src/utils/contextSummarizer.ts +100 -0
  122. package/packages/core/src/utils/skillManager.ts +1 -1
  123. package/packages/core/src/utils/streamSimulator.ts +88 -0
  124. package/packages/core/src/web3/aggregator/providers/ArbitrumBridgeProvider.ts +30 -11
  125. package/packages/core/src/web3/aggregator/providers/OpBridgeProvider.ts +43 -29
  126. package/packages/core/src/web3/aggregator/routeSelector.ts +6 -1
  127. package/packages/core/src/web3/plugins/Web3DefiPlugin.ts +1 -1
  128. package/packages/core/src/web3/plugins/Web3MarketPlugin.ts +6 -125
  129. package/packages/core/src/web3/plugins/Web3SecurityPlugin.ts +1 -1
  130. package/packages/core/src/web3/plugins/Web3WalletPlugin.ts +1 -1
  131. package/packages/core/src/web3/skills/bridgeToken.ts +21 -7
  132. package/packages/core/src/web3/skills/checkAddress.ts +2 -0
  133. package/packages/core/src/web3/skills/checkPortfolio.ts +23 -2
  134. package/packages/core/src/web3/skills/checkSecurity.ts +2 -0
  135. package/packages/core/src/web3/skills/confirmPendingTx.ts +1 -1
  136. package/packages/core/src/web3/skills/createLimitOrder.ts +17 -2
  137. package/packages/core/src/web3/skills/customTx.ts +3 -0
  138. package/packages/core/src/web3/skills/defiLending.ts +2 -0
  139. package/packages/core/src/web3/skills/getBalance.ts +2 -0
  140. package/packages/core/src/web3/skills/getPrice.ts +134 -30
  141. package/packages/core/src/web3/skills/getTxHistory.ts +2 -0
  142. package/packages/core/src/web3/skills/marketAnalysis.ts +45 -188
  143. package/packages/core/src/web3/skills/mintNft.ts +3 -0
  144. package/packages/core/src/web3/skills/provideLiquidity.ts +16 -10
  145. package/packages/core/src/web3/skills/revokeApprovals.ts +2 -0
  146. package/packages/core/src/web3/skills/swapToken.ts +20 -3
  147. package/packages/core/src/web3/skills/transfer.ts +2 -0
  148. package/packages/core/src/web3/skills/yieldVault.ts +2 -0
  149. package/packages/core/src/web3/utils/chains.ts +12 -0
  150. package/packages/core/src/web3/utils/marketEngine.ts +27 -33
  151. package/packages/dashboard/dist/assets/index-Czxksiao.js +18 -0
  152. package/packages/dashboard/dist/assets/index-DK2sTU47.css +1 -0
  153. package/packages/dashboard/dist/index.html +2 -2
  154. package/packages/dashboard/package.json +10 -10
  155. package/packages/mcp-server/dist/server.js +5 -1
  156. package/packages/mcp-server/package.json +6 -6
  157. package/packages/mcp-server/src/server.ts +11 -7
  158. package/packages/ml-engine/__pycache__/config.cpython-313.pyc +0 -0
  159. package/packages/ml-engine/__pycache__/main.cpython-313.pyc +0 -0
  160. package/packages/ml-engine/config.py +59 -0
  161. package/packages/ml-engine/main.py +34 -0
  162. package/packages/ml-engine/requirements.txt +22 -0
  163. package/packages/ml-engine/routers/__init__.py +1 -0
  164. package/packages/ml-engine/routers/__pycache__/__init__.cpython-313.pyc +0 -0
  165. package/packages/ml-engine/routers/__pycache__/cognitive.cpython-313.pyc +0 -0
  166. package/packages/ml-engine/routers/__pycache__/critic.cpython-313.pyc +0 -0
  167. package/packages/ml-engine/routers/__pycache__/llm.cpython-313.pyc +0 -0
  168. package/packages/ml-engine/routers/__pycache__/market.cpython-313.pyc +0 -0
  169. package/packages/ml-engine/routers/__pycache__/memory.cpython-313.pyc +0 -0
  170. package/packages/ml-engine/routers/cognitive.py +98 -0
  171. package/packages/ml-engine/routers/critic.py +111 -0
  172. package/packages/ml-engine/routers/llm.py +38 -0
  173. package/packages/ml-engine/routers/market.py +332 -0
  174. package/packages/ml-engine/routers/memory.py +125 -0
  175. package/packages/policy/package.json +3 -3
  176. package/packages/signer/package.json +16 -6
  177. package/packages/signer/src/NyxoraSigner.ts +161 -0
  178. package/packages/signer/src/index.ts +1 -0
  179. package/packages/signer/src/server.ts +25 -135
  180. package/dist/packages/core/src/agent/honchoDaemon.js +0 -91
  181. package/dist/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +0 -54
  182. package/dist/packages/core/src/gateway/test.js +0 -15
  183. package/dist/packages/core/src/web3/Web3DefiPlugin.js +0 -28
  184. package/dist/packages/core/src/web3/aggregator/aggregatorMainnet.js +0 -260
  185. package/dist/packages/core/src/web3/aggregator/aggregatorTestnet.js +0 -119
  186. package/dist/packages/core/src/web3/skills/nativeOpBridge.js +0 -71
  187. package/packages/core/src/agent/honchoDaemon.ts +0 -96
  188. package/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +0 -41
  189. package/packages/core/src/plugin/registry.test.ts +0 -46
  190. package/packages/core/src/utils/formatter.test.ts +0 -41
  191. package/packages/dashboard/dist/assets/index-CSoNa5cx.css +0 -1
  192. 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', reply_parameters: { message_id: ctx.message.message_id } });
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;
153
+ }
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', reply_parameters: { message_id: ctx.message.message_id } });
160
+ }
161
+ catch { }
162
+ isDrafting = false;
132
163
  }
133
- // Transactions will now use conversational approval (Zero-Latency text prompts) instead of InlineKeyboards.
134
- await ctx.reply(formatToTelegramHTML(response), { parse_mode: 'HTML' });
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, reply_parameters: { message_id: ctx.message.message_id } }).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.', { reply_parameters: { message_id: ctx.message.message_id } }).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) => {
@@ -159,7 +253,7 @@ function startTelegramBot() {
159
253
  const onProgress = async (progressText) => {
160
254
  try {
161
255
  if (!progressMsgId) {
162
- const sent = await ctx.reply(`<i>${progressText.replace(/_/g, '')}</i>`, { parse_mode: 'HTML' });
256
+ const sent = await ctx.reply(`<i>${progressText.replace(/_/g, '')}</i>`, { parse_mode: 'HTML', reply_parameters: { message_id: ctx.message?.message_id } });
163
257
  progressMsgId = sent.message_id;
164
258
  }
165
259
  else {
@@ -172,18 +266,20 @@ function startTelegramBot() {
172
266
  if (progressMsgId) {
173
267
  await ctx.api.deleteMessage(ctx.chat.id, progressMsgId).catch(() => { });
174
268
  }
175
- await ctx.reply(formatToTelegramHTML(response), { parse_mode: 'HTML' });
269
+ await ctx.reply(formatToTelegramHTML(response), { parse_mode: 'HTML', reply_parameters: { message_id: ctx.message?.message_id } });
176
270
  }
177
271
  catch (error) {
178
272
  console.error('[Telegram] Error processing document:', error);
179
- await ctx.reply('❌ Sorry, I failed to download or analyze the document.');
273
+ await ctx.reply('❌ Sorry, I failed to download or analyze the document.', { reply_parameters: { message_id: ctx.message?.message_id } });
180
274
  }
181
275
  });
182
276
  // Transaction approval and rejection are now handled conversationally via the LLM and the confirm_pending_tx tool.
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,55 @@ 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
+ try {
140
+ if (existing) {
141
+ const newConfidence = Math.min(1.0, existing.confidence + (confidence * 0.2));
142
+ this.db.prepare('UPDATE user_personas SET trait = ?, confidence = ?, source = ?, lastUpdated = CURRENT_TIMESTAMP WHERE id = ?').run(value.trim(), newConfidence, source, existing.id);
143
+ }
144
+ else {
145
+ this.db.prepare('INSERT INTO user_personas (trait, category, confidence, source) VALUES (?, ?, ?, ?)').run(value.trim(), category, confidence, source);
146
+ }
147
+ }
148
+ catch (e) {
149
+ // Handle UNIQUE constraint collision if the trait already exists in the database (e.g. from an older version with category 'general')
150
+ if (e.message && e.message.includes('UNIQUE constraint failed')) {
151
+ this.db.prepare('UPDATE user_personas SET category = ?, confidence = ?, source = ?, lastUpdated = CURRENT_TIMESTAMP WHERE trait = ?').run(category, confidence, source, value.trim());
152
+ }
153
+ else {
154
+ throw e;
155
+ }
113
156
  }
114
157
  }
115
158
  getPersonas() {
116
159
  const stmt = this.db.prepare('SELECT * FROM user_personas ORDER BY confidence DESC');
117
160
  return stmt.all();
118
161
  }
162
+ /**
163
+ * Get personas filtered by minimum confidence threshold.
164
+ */
165
+ getStrongPersonas(minConfidence = 0.5) {
166
+ const stmt = this.db.prepare('SELECT * FROM user_personas WHERE confidence >= ? ORDER BY confidence DESC');
167
+ return stmt.all(minConfidence);
168
+ }
169
+ deletePersonaByTrait(keyword) {
170
+ const stmt = this.db.prepare('DELETE FROM user_personas WHERE trait LIKE ?');
171
+ const result = stmt.run(`%${keyword}%`);
172
+ return result.changes || 0;
173
+ }
119
174
  }
120
175
  exports.EpisodicMemoryDB = EpisodicMemoryDB;
121
176
  // 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,13 +5,15 @@ 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,
12
12
  googleWorkspace_1.appendRowToSheetsToolDefinition,
13
13
  googleWorkspace_1.readGoogleDocsToolDefinition,
14
- googleWorkspace_1.readGoogleFormResponsesToolDefinition
14
+ googleWorkspace_1.readGoogleFormResponsesToolDefinition,
15
+ googleWorkspace_1.sendEmailToolDefinition,
16
+ googleWorkspace_1.addCalendarEventToolDefinition
15
17
  ];
16
18
  handlers = {
17
19
  ['read_gmail_inbox']: async (args) => {
@@ -28,6 +30,12 @@ class GoogleWorkspacePlugin {
28
30
  },
29
31
  ['read_google_form_responses']: async (args) => {
30
32
  return await (0, googleWorkspace_1.readGoogleFormResponses)(args.formId);
33
+ },
34
+ ['send_email']: async (args) => {
35
+ return await (0, googleWorkspace_1.sendEmail)(args.to, args.subject, args.body);
36
+ },
37
+ ['add_calendar_event']: async (args) => {
38
+ return await (0, googleWorkspace_1.addCalendarEvent)(args.summary, args.description, args.startTime, args.endTime);
31
39
  }
32
40
  };
33
41
  }
@@ -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
  {