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
@@ -7,6 +7,8 @@ import { Tracker } from '../gateway/tracker';
7
7
  import { episodicDB } from '../memory/episodic';
8
8
  import { isSkillActive } from '../utils/skillManager';
9
9
  import { cognitiveManager } from '../cognitive/cognitiveManager';
10
+ import { ReasoningScratchpad } from './reasoningScratchpad';
11
+ import { compressHistory, needsCompression } from '../utils/contextSummarizer';
10
12
 
11
13
  const EXECUTION_DISCIPLINE = `
12
14
  <tool_persistence>
@@ -23,17 +25,45 @@ NEVER answer the following using only your internal memory — ALWAYS use the re
23
25
  - Real-world current events
24
26
  </mandatory_tool_use>
25
27
 
28
+ <web_search_accuracy>
29
+ When using the search_web tool to look up news, current events, or factual data:
30
+ 1. NEVER pass casual, conversational, or highly localized queries directly to the tool (e.g. do not pass "hasil piala dunia tadi pagi").
31
+ 2. ALWAYS translate and optimize the query into an absolute, highly specific, and globally-understood English search query (e.g. "World Cup 2026 match results June 25 2026").
32
+ 3. Use depth: 2 (deep research) for anything that requires high factual accuracy, such as sports scores, news, or complex topics.
33
+ </web_search_accuracy>
34
+
26
35
  <act_dont_ask>
27
36
  When a user's request has a clear, standard interpretation, take immediate ACTION instead of asking for clarification.
37
+ NEVER show a command as a markdown code block and wait. CALL the tool directly.
38
+ NEVER ask "do you want me to run this?" — just run it.
39
+ NEVER say "you need to run this yourself" — you have direct shell access.
40
+ If a command requires sudo and may need a password, just run it and report what happens.
41
+ Only report failure AFTER actually attempting the tool call and receiving an error.
28
42
  </act_dont_ask>
29
43
 
44
+ <anti_hallucination_execution>
45
+ CRITICAL: It is STRICTLY FORBIDDEN to write a bash/shell command in a markdown code block (e.g. \`\`\`bash ... \`\`\`) as a substitute for calling the run_terminal_command tool.
46
+ Writing a code block does NOT execute anything. It is a lie to the user.
47
+ If you write \`\`\`bash\nsudo apt install steam\n\`\`\` instead of calling run_terminal_command, you are hallucinating execution.
48
+ The ONLY way to run a command is to emit a proper tool_call for run_terminal_command.
49
+ If the tool is available, USE IT. Do not simulate or describe running it.
50
+ </anti_hallucination_execution>
51
+
30
52
  <task_completion>
31
53
  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.
32
54
  NEVER fabricate, hallucinate, or forge tool outputs.
33
55
  </task_completion>
56
+
57
+ <self_correction>
58
+ Before providing a final answer to the user (especially regarding dates, events, news, or factual data), you MUST evaluate your tool results inside a <think> block.
59
+ Ask yourself: "Is my answer based on absolute facts, or circumstantial evidence (e.g., guessing a registration date based on a video upload date)?"
60
+ If the evidence is circumstantial or incomplete, you MUST NOT answer the user. Instead, call the search_web tool again with a highly optimized query and depth=2.
61
+ </self_correction>
34
62
  `;
35
63
 
36
64
 
65
+
66
+
37
67
  import { pluginManager } from '../plugin/registry';
38
68
 
39
69
  import { getPath } from '../config/paths';
@@ -45,45 +75,88 @@ export const logger = new Logger();
45
75
 
46
76
  import { getOpenAI, executeWithRetry } from '../utils/llmUtils';
47
77
 
48
- function getSystemPrompt(context: 'web3' | 'os' | 'general' = 'os', userInput: string = ''): string {
78
+ async function getSystemPrompt(context: 'web3' | 'os' | 'general' = 'os', userInput: string = ''): Promise<string> {
49
79
  const config = loadConfig();
50
80
  const currentDateTime = new Date().toLocaleString('en-US');
51
81
  let basePrompt = `You are Nyxora's OS Agent (System & Automation Specialist).
52
82
  The current real-world date and time is: ${currentDateTime}.
53
83
 
84
+ You are running LOCALLY on the user's own computer — NOT on a remote cloud server. The 'run_terminal_command' tool executes shell commands directly on this machine, the same physical machine the user is sitting at. You have FULL local shell access. When asked to install software, manage files, or perform any OS task, you MUST use run_terminal_command immediately. NEVER claim you cannot access the user's system.
85
+
54
86
  Reason internally. Never reveal private reasoning. Provide only concise conclusions, assumptions, and actionable steps.
55
87
 
56
88
  [OS EXECUTION WORKFLOW]
57
89
  CRITICAL RULE 1: NEVER expose internal JSON tool calls. Explain the outcome naturally.
58
- CRITICAL RULE 2: STRICT LANGUAGE MATCHING. Reply in the exact same language as the user's LATEST prompt.
90
+ CRITICAL RULE 2: STRICT LANGUAGE MATCHING. Reply in the exact same language as the user's LATEST prompt, UNLESS the Episodic Memories or Cognitive Skills specify a strict language preference.
59
91
  CRITICAL RULE 3: FILE SYSTEM SAFETY. You are STRICTLY FORBIDDEN from modifying config.yaml, rpc_key.yaml, or policy.yaml using terminal commands like sed or echo.
60
92
  CRITICAL RULE 4: CRON JOBS VS LIMIT ORDERS. Do NOT use schedule_task for price-based trading triggers. Use schedule_task for time-based recurring tasks.
61
93
  CRITICAL RULE 5: TOOL CONFIDENCE. NEVER fabricate file contents or command outputs.
62
94
 
95
+ [SUDO & PACKAGE INSTALL STRATEGY]
96
+ This tool runs in a NON-INTERACTIVE shell (no TTY). Therefore:
97
+ - ALWAYS prefix apt/apt-get commands with: DEBIAN_FRONTEND=noninteractive
98
+ - ALWAYS use the -y flag for package installations to auto-confirm.
99
+ - If a command fails with "sudo: a password is required" or similar, DO NOT promise to retry without actually retrying. Instead:
100
+ 1. First retry with: echo 'USER_PASSWORD' | sudo -S <command> — but since you don't know the password, skip this.
101
+ 2. Instead, try running the command WITHOUT sudo if possible (e.g. for user-space tools).
102
+ 3. If sudo is truly required and unavailable, clearly tell the user EXACTLY what command to run manually in their terminal, with a copy-paste ready command. Do not just say it failed without providing a solution.
103
+ - NEVER promise to retry ("let me try again", "I'll run it again", etc.) without immediately making another tool_call in the same response.
104
+
63
105
  ${EXECUTION_DISCIPLINE}
64
106
  `;
65
107
 
108
+
66
109
  // Inject Active Cognitive Skills
67
110
  const activeSOP = cognitiveManager.loadActiveCognitiveSkills(userInput);
68
111
  if (activeSOP) {
69
112
  basePrompt += `\n\n[ACTIVE COGNITIVE SKILLS]\n${activeSOP}\n`;
70
113
  }
71
114
 
72
- // Inject Episodic Memories
115
+ // Inject Episodic Memories via Python RAG
73
116
  try {
74
- const recentMemories = episodicDB.getMemories().slice(0, 10);
75
- if (recentMemories.length > 0) {
76
- basePrompt += `
77
-
78
- --- EPISODIC MEMORIES (SMART SUGGESTIONS) ---
79
- `;
80
- recentMemories.forEach(mem => {
81
- basePrompt += `- [${mem.category.toUpperCase()}] ${mem.fact} (Confidence: ${(mem.confidence * 100).toFixed(0)}%)
82
- `;
83
- });
117
+ const ragRes = await fetch('http://127.0.0.1:8000/memory/rag', {
118
+ method: 'POST',
119
+ headers: { 'Content-Type': 'application/json' },
120
+ body: JSON.stringify({ query: userInput, top_k: 5 })
121
+ });
122
+ if (ragRes.ok) {
123
+ const ragData = await ragRes.json();
124
+ if (ragData.memories && ragData.memories.length > 0) {
125
+ basePrompt += `\n\n--- EPISODIC MEMORIES (SMART SUGGESTIONS) ---\n`;
126
+ ragData.memories.forEach((mem: string) => {
127
+ basePrompt += `- ${mem}\n`;
128
+ });
129
+ }
130
+ }
131
+ } catch (e) {
132
+ // Fallback or ignore if Python ML engine is down
133
+ }
134
+ // Inject User Information & Personas from user.md
135
+ try {
136
+ const userMdPath = getPath('user.md');
137
+ if (fs.existsSync(userMdPath)) {
138
+ const userInstructions = fs.readFileSync(userMdPath, 'utf8');
139
+ basePrompt += `\n\n--- USER INFORMATION & PREFERENCES ---\n${userInstructions}\n`;
84
140
  }
85
- } catch {}
141
+ } catch (e) {
142
+ // Ignore error
143
+ }
86
144
 
145
+ // HIGHEST PRIORITY: Inject observed user communication style (NyxDaemon)
146
+ try {
147
+ const strongPersonas = episodicDB.getStrongPersonas(0.5);
148
+ if (strongPersonas.length > 0) {
149
+ basePrompt += `\n\n--- ⚡ OVERRIDE: USER COMMUNICATION STYLE (HIGHEST PRIORITY — OVERRIDES ALL RULES ABOVE) ---\n`;
150
+ basePrompt += `CRITICAL: These are CONFIRMED user preferences observed across multiple conversations. You MUST apply them IMMEDIATELY and CONSISTENTLY, overriding any default tone or style instructions above.\n\n`;
151
+ strongPersonas.forEach(p => {
152
+ const label = p.category ? `[${p.category.toUpperCase()}]` : '[PREFERENCE]';
153
+ basePrompt += `${label} ${p.trait}\n`;
154
+ });
155
+ }
156
+ } catch (e) {
157
+ // Ignore
158
+ }
159
+
87
160
  return basePrompt;
88
161
  }
89
162
 
@@ -92,33 +165,70 @@ export async function processOsIntent(input: string, role: 'user' | 'system' = '
92
165
  // Add input to memory
93
166
  logger.addEntry({ role, content: input }, sessionId);
94
167
 
95
- const history = logger.getHistory(sessionId);
96
-
97
- // Format messages for OpenAI
168
+ // --- MULTILINGUAL USER CORRECTION DETECTION ---
169
+ const correctionSignals = [
170
+ // ID
171
+ 'salah', 'ngawur', 'keliru', 'bukan', 'tidak benar', 'perbaiki', 'coba lagi',
172
+ // EN
173
+ 'wrong', 'incorrect', 'mistake', 'not right', 'false', 'bad', 'fix', 'try again',
174
+ // ES & FR
175
+ 'incorrecto', 'mal', 'equivocado', 'error', 'falso', 'faux', 'erreur', 'mauvais',
176
+ // DE & RU
177
+ 'falsch', 'inkorrekt', 'fehler', 'ошибка', 'неправильно', 'неверно',
178
+ // JP & ZH
179
+ '違う', '間違い', 'やり直して', '错误', '不对'
180
+ ];
181
+ if (role === 'user' && correctionSignals.some(s => input.toLowerCase().includes(s))) {
182
+ logger.addEntry({
183
+ role: 'system' as any,
184
+ content: `[USER CORRECTION DETECTED] The user indicated your previous answer was WRONG, STALE, or INACCURATE.
185
+ CRITICAL INSTRUCTIONS:
186
+ 1. Do NOT just apologize and repeat the same data from your memory.
187
+ 2. The data in your training memory or previous tool calls is likely stale/incorrect.
188
+ 3. You MUST call a tool (like search_web or others) NOW to verify the facts with FRESH data.
189
+ 4. Base your new answer strictly on the NEW tool results.`
190
+ }, sessionId);
191
+ }
192
+
98
193
  let activeTools = [...pluginManager.getAllToolDefinitions()];
99
194
  activeTools = activeTools.filter(t => isSkillActive(t.function.name));
100
195
 
101
- const { sanitizeHistoryForLLM } = require('../utils/historySanitizer');
102
- const sanitizedHistory = sanitizeHistoryForLLM(history, activeTools, config.llm.provider);
196
+ // P1: Init reasoning scratchpad for this request
197
+ const scratchpad = new ReasoningScratchpad();
103
198
 
104
- let messages: any[] = [
105
- { role: 'system', content: getSystemPrompt('os', input) },
106
- ...sanitizedHistory
107
- ];
199
+ // P3: Build system prompt ONCE per request — not per turn
200
+ const cachedSystemPrompt = await getSystemPrompt('os', input);
201
+
202
+ const { sanitizeHistoryForLLM } = require('../utils/historySanitizer');
108
203
 
109
204
  try {
110
205
  let turnCount = 0;
111
206
  const MAX_TURNS = 10;
207
+ let consecutiveToolErrors = 0;
208
+ let criticHasFired = false; // Critic Pass hanya aktif 1x per request
112
209
 
113
210
  while (turnCount < MAX_TURNS) {
114
211
  turnCount++;
115
212
  const currentHistory = logger.getHistory(sessionId);
116
- const sanitizedHistory = sanitizeHistoryForLLM(currentHistory, activeTools, config.llm.provider);
213
+
214
+ // P6: Compress history if conversation is too long
215
+ const historyToUse = needsCompression(currentHistory)
216
+ ? await compressHistory(currentHistory)
217
+ : currentHistory;
218
+
219
+ const sanitizedHistory = sanitizeHistoryForLLM(historyToUse, activeTools, config.llm.provider);
220
+
221
+ // P1: Inject scratchpad into system prompt for turns > 1
222
+ const sysPrompt = turnCount === 1
223
+ ? cachedSystemPrompt
224
+ : cachedSystemPrompt + scratchpad.getInjection();
225
+
117
226
  const messages: any[] = [
118
- { role: 'system', content: getSystemPrompt('os', input) },
227
+ { role: 'system', content: sysPrompt },
119
228
  ...sanitizedHistory
120
229
  ];
121
230
 
231
+
122
232
  const response = await executeWithRetry(async (client) => {
123
233
  return await client.chat({
124
234
  model: config.llm.model,
@@ -139,17 +249,45 @@ export async function processOsIntent(input: string, role: 'user' | 'system' = '
139
249
  }
140
250
  Tracker.addEvent('llm.response', { provider: config.llm.provider, tool_calls: responseMessage.tool_calls?.length || 0 });
141
251
 
252
+ // P1: Capture <think> blocks for scratchpad, get clean content
253
+ const cleanedContent = scratchpad.capture(responseMessage.content || '', turnCount);
254
+
142
255
  logger.addEntry({
143
256
  role: 'assistant',
144
- content: responseMessage.content || "",
257
+ content: cleanedContent || '',
145
258
  tool_calls: responseMessage.tool_calls,
146
259
  }, sessionId);
147
260
 
148
261
  if (!responseMessage.tool_calls || responseMessage.tool_calls.length === 0) {
149
- let finalContent = responseMessage.content || "No response generated.";
150
- finalContent = finalContent.replace(/<(think|thought|thinking|reasoning|analysis|reflection)>[\s\S]*?<\/\1>\n?/gi, '');
151
- finalContent = finalContent.trim();
152
- return finalContent;
262
+ // --- CRITIC PASS (Self-Improvement) ---
263
+ const isLongResponse = (cleanedContent?.length ?? 0) > 100;
264
+ if (isLongResponse && !criticHasFired) {
265
+ criticHasFired = true;
266
+ try {
267
+ const criticRes = await fetch('http://127.0.0.1:8000/cognitive/critic', {
268
+ method: 'POST',
269
+ headers: { 'Content-Type': 'application/json' },
270
+ body: JSON.stringify({ user_input: input, draft_answer: cleanedContent, current_utc_datetime: new Date().toISOString() })
271
+ });
272
+ if (criticRes.ok) {
273
+ const evaluation = await criticRes.json();
274
+ if (evaluation.needs_revision) {
275
+ console.log(pc.cyan(`[🧠 Critic] Revision needed. Confidence: ${evaluation.factual_confidence?.toFixed(2)}. Completeness: ${evaluation.completeness?.toFixed(2)}. Re-generating...`));
276
+ logger.addEntry({
277
+ role: 'system' as any,
278
+ content: `[SELF-CRITIQUE — MANDATORY REVISION] Your previous answer was REJECTED. Issues:\n${evaluation.revision_instructions}\n\nCRITICAL REVISION RULES:\n1. Look at the tool results (search_web, etc.) ALREADY in this conversation history above.\n2. Base your revised answer EXCLUSIVELY on those tool results — NEVER use training data memory for facts, dates, or events.\n3. If tool results contain the answer, state it directly and confidently. Do NOT say an event hasn't happened if the tool results show it has.\n4. Do NOT call any tools again — the results are already in your history. USE THEM NOW.`
279
+ }, sessionId);
280
+ continue; // Loop kembali ke Generator untuk revisi
281
+ } else {
282
+ console.log(pc.green(`[🧠 Critic] Passed. Confidence: ${evaluation.factual_confidence?.toFixed(2)}, Completeness: ${evaluation.completeness?.toFixed(2)}.`));
283
+ }
284
+ }
285
+ } catch {
286
+ // Python ML Engine tidak aktif — skip Critic, lanjut seperti biasa
287
+ }
288
+ }
289
+ // --- END CRITIC PASS ---
290
+ return cleanedContent || 'No response generated.';
153
291
  }
154
292
 
155
293
  let canFastReturnAll = true;
@@ -234,8 +372,29 @@ export async function processOsIntent(input: string, role: 'user' | 'system' = '
234
372
  }
235
373
  }
236
374
 
237
- // V2 Optimization (Expanded in v1.7.4): Zero-LLM Fast Return for data-heavy and read-only tools
238
- // If all tools already return perfectly formatted markdown, skip the second LLM call to save 5-10s latency!
375
+ // P4: Self-reflection if ALL tools failed, inject reflection before next turn
376
+ const allFailed = accumulatedResults.length > 0 && accumulatedResults.every(
377
+ r => r.startsWith('Error') || r.includes('[System Error]') || r.includes('[Security Blocked]')
378
+ );
379
+ if (allFailed) {
380
+ consecutiveToolErrors++;
381
+ const reflection = `[SELF-REFLECTION] All ${accumulatedResults.length} tool call(s) failed (attempt ${consecutiveToolErrors}). ` +
382
+ `Errors: ${accumulatedResults.join(' | ')}. ` +
383
+ `Analyze WHY each failed. Options: (1) retry with corrected params, (2) use alternative tool, (3) inform user clearly. ` +
384
+ `Do NOT repeat the exact same failed call.`;
385
+ logger.addEntry({ role: 'system' as any, content: reflection }, sessionId);
386
+ console.log(pc.magenta(`[Self-Reflection] Turn ${turnCount}: all tools failed, injecting reflection.`));
387
+
388
+ if (consecutiveToolErrors >= 2) {
389
+ const errorSummary = `⚠️ Unable to complete this request after multiple attempts.\n${accumulatedResults.join('\n')}`;
390
+ logger.addEntry({ role: 'assistant', content: errorSummary }, sessionId);
391
+ return errorSummary;
392
+ }
393
+ } else {
394
+ consecutiveToolErrors = 0;
395
+ }
396
+
397
+ // V2 Optimization: Zero-LLM Fast Return for transaction tools
239
398
  if (canFastReturnAll && accumulatedResults.length > 0) {
240
399
  const finalContent = accumulatedResults.join('\n\n---\n\n');
241
400
  logger.addEntry({ role: 'assistant', content: finalContent }, sessionId);
@@ -261,3 +420,193 @@ export async function processOsIntent(input: string, role: 'user' | 'system' = '
261
420
  return errorMsg;
262
421
  }
263
422
  }
423
+
424
+ export async function processOsIntentStream(
425
+ input: string,
426
+ onChunk: (text: string) => void,
427
+ onProgress?: (msg: string) => void,
428
+ sessionId?: string
429
+ ): Promise<string> {
430
+ const config = loadConfig();
431
+ logger.addEntry({ role: 'user', content: input }, sessionId);
432
+
433
+ // --- MULTILINGUAL USER CORRECTION DETECTION ---
434
+ const correctionSignals = [
435
+ // ID
436
+ 'salah', 'ngawur', 'keliru', 'bukan', 'tidak benar', 'perbaiki', 'coba lagi',
437
+ // EN
438
+ 'wrong', 'incorrect', 'mistake', 'not right', 'false', 'bad', 'fix', 'try again',
439
+ // ES & FR
440
+ 'incorrecto', 'mal', 'equivocado', 'error', 'falso', 'faux', 'erreur', 'mauvais',
441
+ // DE & RU
442
+ 'falsch', 'inkorrekt', 'fehler', 'ошибка', 'неправильно', 'неверно',
443
+ // JP & ZH
444
+ '違う', '間違い', 'やり直して', '错误', '不对'
445
+ ];
446
+ if (correctionSignals.some(s => input.toLowerCase().includes(s))) {
447
+ logger.addEntry({
448
+ role: 'system' as any,
449
+ content: `[USER CORRECTION DETECTED] The user indicated your previous answer was WRONG, STALE, or INACCURATE.
450
+ CRITICAL INSTRUCTIONS:
451
+ 1. Do NOT just apologize and repeat the same data from your memory.
452
+ 2. The data in your training memory or previous tool calls is likely stale/incorrect.
453
+ 3. You MUST call a tool (like search_web or others) NOW to verify the facts with FRESH data.
454
+ 4. Base your new answer strictly on the NEW tool results.`
455
+ }, sessionId);
456
+ }
457
+
458
+ const pluginTools = pluginManager.getAllToolDefinitions();
459
+ let activeTools = [...pluginTools].filter(t => isSkillActive(t.function.name));
460
+
461
+ const { sanitizeHistoryForLLM } = require('../utils/historySanitizer');
462
+
463
+ try {
464
+ let turnCount = 0;
465
+ const MAX_TURNS = 10;
466
+ let fullResponse = '';
467
+ let criticHasFiredStream = false; // Critic Pass hanya aktif 1x per request
468
+
469
+ while (turnCount < MAX_TURNS) {
470
+ turnCount++;
471
+ const currentHistory = logger.getHistory(sessionId);
472
+ const sanitizedHistory = sanitizeHistoryForLLM(currentHistory, activeTools, config.llm.provider);
473
+ const messages: any[] = [
474
+ { role: 'system', content: await getSystemPrompt('os', input) },
475
+ ...sanitizedHistory
476
+ ];
477
+
478
+ let streamedContent = '';
479
+ const response = await executeWithRetry(async (client) => {
480
+ return await client.stream(
481
+ { model: config.llm.model, temperature: config.llm.temperature, messages, tools: activeTools },
482
+ (chunk: string) => {
483
+ streamedContent += chunk;
484
+ onChunk(chunk);
485
+ }
486
+ );
487
+ });
488
+
489
+ const responseMessage = response.message;
490
+
491
+ if (turnCount === 1) Tracker.addMessage();
492
+ if (response.usage?.total_tokens) Tracker.addTokens(response.usage.total_tokens, config.llm.provider);
493
+ Tracker.addEvent('llm.response', { provider: config.llm.provider, tool_calls: responseMessage.tool_calls?.length || 0 });
494
+
495
+ logger.addEntry({
496
+ role: 'assistant',
497
+ content: responseMessage.content || '',
498
+ tool_calls: responseMessage.tool_calls,
499
+ }, sessionId);
500
+
501
+ if (!responseMessage.tool_calls || responseMessage.tool_calls.length === 0) {
502
+ let finalContent = responseMessage.content || 'No response generated.';
503
+ finalContent = finalContent.replace(/<(think|thought|thinking|reasoning|analysis|reflection)[\s\S]*?<\/\1>\n?/gi, '').trim();
504
+
505
+ // --- CRITIC PASS (Self-Improvement) ---
506
+ const isLongResponseStream = finalContent.length > 100;
507
+ if (isLongResponseStream && !criticHasFiredStream) {
508
+ criticHasFiredStream = true;
509
+ try {
510
+ const criticRes = await fetch('http://127.0.0.1:8000/cognitive/critic', {
511
+ method: 'POST',
512
+ headers: { 'Content-Type': 'application/json' },
513
+ body: JSON.stringify({ user_input: input, draft_answer: finalContent, current_utc_datetime: new Date().toISOString() })
514
+ });
515
+ if (criticRes.ok) {
516
+ const evaluation = await criticRes.json();
517
+ if (evaluation.needs_revision) {
518
+ console.log(pc.cyan(`[🧠 Critic] Revision needed. Confidence: ${evaluation.factual_confidence?.toFixed(2)}. Completeness: ${evaluation.completeness?.toFixed(2)}. Re-generating...`));
519
+ logger.addEntry({
520
+ role: 'system' as any,
521
+ content: `[SELF-CRITIQUE — MANDATORY REVISION] Your previous answer was REJECTED. Issues:\n${evaluation.revision_instructions}\n\nCRITICAL REVISION RULES:\n1. Look at the tool results (search_web, etc.) ALREADY in this conversation history above.\n2. Base your revised answer EXCLUSIVELY on those tool results — NEVER use training data memory for facts, dates, or events.\n3. If tool results contain the answer, state it directly and confidently. Do NOT say an event hasn't happened if the tool results show it has.\n4. Do NOT call any tools again — the results are already in your history. USE THEM NOW.`
522
+ }, sessionId);
523
+ continue; // Loop kembali ke Generator untuk revisi
524
+ } else {
525
+ console.log(pc.green(`[🧠 Critic] Passed. Confidence: ${evaluation.factual_confidence?.toFixed(2)}, Completeness: ${evaluation.completeness?.toFixed(2)}.`));
526
+ }
527
+ }
528
+ } catch {
529
+ // Python ML Engine tidak aktif — skip Critic, lanjut seperti biasa
530
+ }
531
+ }
532
+ // --- END CRITIC PASS ---
533
+
534
+ fullResponse = finalContent;
535
+ break;
536
+ }
537
+
538
+ // Tool calls detected — pause stream visually and execute tools
539
+ const fastReturnTools = ['transfer_token', 'transfer_native', 'swap_token', 'bridge_token', 'mint_nft', 'custom_tx', 'revoke_approval', 'supply_aave', 'deposit_yield_vault', 'provide_liquidity_v3'];
540
+ let canFastReturnAll = true;
541
+ const accumulatedResults: string[] = [];
542
+
543
+ for (const _toolCall of responseMessage.tool_calls) {
544
+ const toolCall = _toolCall as any;
545
+ const toolName = toolCall.function.name;
546
+ let result = '';
547
+ let args: any = {};
548
+
549
+ console.log(pc.yellow(`[⚡ Tool Execution] AI is calling ${toolName}...`));
550
+ if (onProgress) onProgress(`_⚡ Running tool: ${toolName}..._`);
551
+
552
+ try {
553
+ let argStr = toolCall.function.arguments;
554
+ if (argStr && !argStr.trim().endsWith('}')) argStr += '}';
555
+ args = JSON.parse(argStr);
556
+ } catch (parseError: any) {
557
+ result = `[System Error] Arguments for ${toolName} must be valid JSON. Error: ${parseError.message}`;
558
+ logger.addEntry({ role: 'tool', tool_call_id: toolCall.id, content: result }, sessionId);
559
+ continue;
560
+ }
561
+
562
+ if (!isSkillActive(toolName)) {
563
+ result = `[System Error] Access denied: Skill '${toolName}' is currently disabled.`;
564
+ logger.addEntry({ role: 'tool', tool_call_id: toolCall.id, content: result }, sessionId);
565
+ continue;
566
+ }
567
+
568
+ try {
569
+ const pluginResult = await pluginManager.executeTool(toolName, args, { sessionId });
570
+ result = pluginResult !== null ? pluginResult : `Error: Tool ${toolName} is not implemented.`;
571
+ if (result.includes('[Security Blocked]') || result.startsWith('Error:')) {
572
+ console.log(pc.red(`[❌ Failed] Tool ${toolName} returned an error or was blocked.`));
573
+ } else {
574
+ console.log(pc.green(`[✅ Success] Tool ${toolName} executed successfully.`));
575
+ }
576
+ } catch (toolError: any) {
577
+ result = `Error executing ${toolName}: ${toolError.message}`;
578
+ console.error(pc.red(`[❌ Error Crash] Execution of ${toolName} failed: ${toolError.message}`));
579
+ }
580
+
581
+ logger.addEntry({ role: 'tool', tool_call_id: toolCall.id, name: toolName, content: result }, sessionId);
582
+ accumulatedResults.push(result);
583
+ if (!fastReturnTools.includes(toolName)) canFastReturnAll = false;
584
+ }
585
+
586
+ if (canFastReturnAll && accumulatedResults.length > 0) {
587
+ const finalContent = accumulatedResults.join('\n\n---\n\n');
588
+ logger.addEntry({ role: 'assistant', content: finalContent }, sessionId);
589
+ onChunk(finalContent);
590
+ fullResponse = finalContent;
591
+ break;
592
+ }
593
+ }
594
+
595
+ if (!fullResponse) {
596
+ const maxTurnMsg = '⚠️ Reached maximum interaction limit (10 turns). Please be more specific.';
597
+ logger.addEntry({ role: 'assistant', content: maxTurnMsg }, sessionId);
598
+ fullResponse = maxTurnMsg;
599
+ }
600
+
601
+ return fullResponse;
602
+ } catch (error: any) {
603
+ console.error('LLM Stream Error:', error);
604
+ const status = error?.status || error?.response?.status;
605
+ let errorMsg = '⚠️ All models are temporarily rate-limited. Please try again in a few minutes.';
606
+ if (status === 400 || (error.message && error.message.toLowerCase().includes('invalid'))) {
607
+ errorMsg = '⚠️ Failed to parse instruction. Please describe your command more specifically.';
608
+ }
609
+ logger.addEntry({ role: 'assistant', content: errorMsg }, sessionId);
610
+ return errorMsg;
611
+ }
612
+ }