nyxora 26.7.4 → 26.7.8

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 (159) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/README.md +43 -8
  3. package/dist/launcher.js +67 -9
  4. package/dist/packages/core/src/agent/bridgeWatcher.js +1 -1
  5. package/dist/packages/core/src/agent/cronManager.js +1 -1
  6. package/dist/packages/core/src/agent/llmProvider.js +78 -7
  7. package/dist/packages/core/src/agent/nyxDaemon.js +2 -2
  8. package/dist/packages/core/src/agent/osAgent.js +172 -206
  9. package/dist/packages/core/src/agent/promptBuilder.js +452 -0
  10. package/dist/packages/core/src/agent/reasoning.js +155 -208
  11. package/dist/packages/core/src/agent/reasoningScratchpad.js +19 -2
  12. package/dist/packages/core/src/agent/threatPatterns.js +106 -0
  13. package/dist/packages/core/src/agent/web3Agent.js +81 -115
  14. package/dist/packages/core/src/agent/workspaceUtils.js +56 -0
  15. package/dist/packages/core/src/channels/ChannelManager.js +36 -0
  16. package/dist/packages/core/src/channels/discordAdapter.js +81 -0
  17. package/dist/packages/core/src/channels/googlechatAdapter.js +45 -0
  18. package/dist/packages/core/src/channels/imessageAdapter.js +34 -0
  19. package/dist/packages/core/src/channels/index.js +89 -0
  20. package/dist/packages/core/src/channels/ircAdapter.js +34 -0
  21. package/dist/packages/core/src/channels/lineAdapter.js +133 -0
  22. package/dist/packages/core/src/channels/matrixAdapter.js +34 -0
  23. package/dist/packages/core/src/channels/mattermostAdapter.js +45 -0
  24. package/dist/packages/core/src/channels/msteamsAdapter.js +45 -0
  25. package/dist/packages/core/src/channels/nextcloudtalkAdapter.js +45 -0
  26. package/dist/packages/core/src/channels/nostrAdapter.js +34 -0
  27. package/dist/packages/core/src/channels/qqbotAdapter.js +34 -0
  28. package/dist/packages/core/src/channels/slackAdapter.js +116 -0
  29. package/dist/packages/core/src/channels/smsAdapter.js +45 -0
  30. package/dist/packages/core/src/channels/synologychatAdapter.js +45 -0
  31. package/dist/packages/core/src/channels/telegram.js +593 -0
  32. package/dist/packages/core/src/channels/twitchAdapter.js +34 -0
  33. package/dist/packages/core/src/channels/voicecallAdapter.js +45 -0
  34. package/dist/packages/core/src/channels/whatsappAdapter.js +136 -0
  35. package/dist/packages/core/src/channels/zaloAdapter.js +45 -0
  36. package/dist/packages/core/src/config/parser.js +2 -1
  37. package/dist/packages/core/src/gateway/chat.js +10 -2
  38. package/dist/packages/core/src/gateway/cli.js +4 -1
  39. package/dist/packages/core/src/gateway/doctor.js +56 -22
  40. package/dist/packages/core/src/gateway/googleAuthModule.js +111 -13
  41. package/dist/packages/core/src/gateway/server.js +139 -3
  42. package/dist/packages/core/src/gateway/setup-ml.js +65 -2
  43. package/dist/packages/core/src/gateway/setup.js +61 -22
  44. package/dist/packages/core/src/gateway/telegram.js +21 -48
  45. package/dist/packages/core/src/memory/episodic.js +4 -0
  46. package/dist/packages/core/src/memory/logger.js +27 -9
  47. package/dist/packages/core/src/plugin/PluginManager.js +46 -16
  48. package/dist/packages/core/src/system/plugins/GoogleWorkspacePlugin.js +69 -30
  49. package/dist/packages/core/src/system/plugins/SystemNotesPlugin.js +148 -0
  50. package/dist/packages/core/src/system/plugins/SystemSocialPlugin.js +2 -14
  51. package/dist/packages/core/src/system/plugins/SystemWebPlugin.js +0 -5
  52. package/dist/packages/core/src/system/plugins/SystemWorkspacePlugin.js +25 -6
  53. package/dist/packages/core/src/system/skills/analyzeImage.js +82 -0
  54. package/dist/packages/core/src/system/skills/fileDownloader.js +45 -0
  55. package/dist/packages/core/src/system/skills/generateExcel.js +1 -1
  56. package/dist/packages/core/src/system/skills/googleWorkspace.js +278 -271
  57. package/dist/packages/core/src/system/skills/playbookManager.js +269 -0
  58. package/dist/packages/core/src/system/skills/telegramUpload.js +25 -0
  59. package/dist/packages/core/src/utils/fileLinker.js +57 -0
  60. package/dist/packages/core/src/utils/historySanitizer.js +19 -5
  61. package/dist/packages/core/src/utils/llmUtils.js +5 -4
  62. package/dist/packages/core/src/utils/skillManager.js +12 -4
  63. package/dist/packages/core/src/utils/streamSimulator.js +40 -40
  64. package/dist/packages/core/src/web3/skills/checkPortfolio.js +7 -1
  65. package/dist/packages/core/src/web3/skills/getTxHistory.js +44 -7
  66. package/dist/packages/core/src/web3/utils/vaultClient.js +20 -22
  67. package/dist/packages/policy/src/server.js +38 -51
  68. package/dist/packages/signer/src/server.js +32 -15
  69. package/launcher.ts +61 -9
  70. package/package.json +7 -7
  71. package/packages/core/package.json +27 -9
  72. package/packages/core/src/agent/bridgeWatcher.ts +1 -1
  73. package/packages/core/src/agent/cronManager.ts +1 -1
  74. package/packages/core/src/agent/llmProvider.ts +87 -7
  75. package/packages/core/src/agent/nyxDaemon.ts +3 -3
  76. package/packages/core/src/agent/osAgent.ts +180 -209
  77. package/packages/core/src/agent/promptBuilder.ts +476 -0
  78. package/packages/core/src/agent/reasoning.ts +156 -213
  79. package/packages/core/src/agent/reasoningScratchpad.ts +21 -2
  80. package/packages/core/src/agent/threatPatterns.ts +115 -0
  81. package/packages/core/src/agent/web3Agent.ts +77 -115
  82. package/packages/core/src/agent/workspaceUtils.ts +53 -0
  83. package/packages/core/src/channels/ChannelManager.ts +45 -0
  84. package/packages/core/src/channels/googlechatAdapter.ts +48 -0
  85. package/packages/core/src/channels/imessageAdapter.ts +37 -0
  86. package/packages/core/src/channels/index.ts +57 -0
  87. package/packages/core/src/channels/ircAdapter.ts +37 -0
  88. package/packages/core/src/channels/lineAdapter.ts +111 -0
  89. package/packages/core/src/channels/matrixAdapter.ts +37 -0
  90. package/packages/core/src/channels/mattermostAdapter.ts +48 -0
  91. package/packages/core/src/channels/msteamsAdapter.ts +48 -0
  92. package/packages/core/src/channels/nextcloudtalkAdapter.ts +48 -0
  93. package/packages/core/src/channels/nostrAdapter.ts +37 -0
  94. package/packages/core/src/channels/qqbotAdapter.ts +37 -0
  95. package/packages/core/src/channels/slackAdapter.ts +92 -0
  96. package/packages/core/src/channels/smsAdapter.ts +48 -0
  97. package/packages/core/src/channels/synologychatAdapter.ts +48 -0
  98. package/packages/core/src/channels/telegram.ts +643 -0
  99. package/packages/core/src/channels/twitchAdapter.ts +37 -0
  100. package/packages/core/src/channels/voicecallAdapter.ts +48 -0
  101. package/packages/core/src/channels/whatsappAdapter.ts +113 -0
  102. package/packages/core/src/channels/zaloAdapter.ts +48 -0
  103. package/packages/core/src/config/parser.ts +7 -1
  104. package/packages/core/src/gateway/chat.ts +10 -2
  105. package/packages/core/src/gateway/cli.ts +4 -1
  106. package/packages/core/src/gateway/doctor.ts +56 -22
  107. package/packages/core/src/gateway/googleAuthModule.ts +113 -11
  108. package/packages/core/src/gateway/server.ts +146 -3
  109. package/packages/core/src/gateway/setup-ml.ts +65 -4
  110. package/packages/core/src/gateway/setup.ts +60 -22
  111. package/packages/core/src/memory/episodic.ts +4 -0
  112. package/packages/core/src/memory/logger.ts +26 -9
  113. package/packages/core/src/plugin/PluginManager.ts +78 -16
  114. package/packages/core/src/system/plugins/GoogleWorkspacePlugin.ts +36 -45
  115. package/packages/core/src/system/plugins/SystemNotesPlugin.ts +141 -0
  116. package/packages/core/src/system/plugins/SystemSocialPlugin.ts +2 -14
  117. package/packages/core/src/system/plugins/SystemWebPlugin.ts +0 -5
  118. package/packages/core/src/system/plugins/SystemWorkspacePlugin.ts +25 -6
  119. package/packages/core/src/system/skills/analyzeImage.ts +79 -0
  120. package/packages/core/src/system/skills/fileDownloader.ts +43 -0
  121. package/packages/core/src/system/skills/generateExcel.ts +1 -1
  122. package/packages/core/src/system/skills/googleWorkspace.ts +262 -283
  123. package/packages/core/src/system/skills/playbookManager.ts +285 -0
  124. package/packages/core/src/system/skills/telegramUpload.ts +23 -0
  125. package/packages/core/src/utils/fileLinker.ts +48 -0
  126. package/packages/core/src/utils/historySanitizer.ts +21 -5
  127. package/packages/core/src/utils/llmUtils.ts +5 -4
  128. package/packages/core/src/utils/skillManager.ts +14 -4
  129. package/packages/core/src/utils/streamSimulator.ts +46 -44
  130. package/packages/core/src/web3/skills/checkPortfolio.ts +8 -1
  131. package/packages/core/src/web3/skills/getTxHistory.ts +42 -8
  132. package/packages/core/src/web3/utils/vaultClient.ts +23 -22
  133. package/packages/dashboard/dist/assets/index-Dg9eiK4h.css +1 -0
  134. package/packages/dashboard/dist/assets/index-Dq64NWt0.js +26 -0
  135. package/packages/dashboard/dist/index.html +2 -2
  136. package/packages/dashboard/package.json +1 -1
  137. package/packages/mcp-server/package.json +1 -1
  138. package/packages/ml-engine/__pycache__/main.cpython-313.pyc +0 -0
  139. package/packages/ml-engine/main.py +4 -1
  140. package/packages/ml-engine/routers/__pycache__/background_review.cpython-313.pyc +0 -0
  141. package/packages/ml-engine/routers/__pycache__/llm.cpython-313.pyc +0 -0
  142. package/packages/ml-engine/routers/__pycache__/memory_writer.cpython-313.pyc +0 -0
  143. package/packages/ml-engine/routers/__pycache__/skill_manager.cpython-313.pyc +0 -0
  144. package/packages/ml-engine/routers/background_review.py +121 -0
  145. package/packages/ml-engine/routers/llm.py +15 -1
  146. package/packages/ml-engine/routers/memory_writer.py +72 -0
  147. package/packages/ml-engine/routers/skill_manager.py +123 -0
  148. package/packages/policy/package.json +1 -1
  149. package/packages/policy/src/server.ts +43 -49
  150. package/packages/signer/package.json +1 -1
  151. package/packages/signer/src/server.ts +32 -13
  152. package/packages/core/src/gateway/telegram.ts +0 -357
  153. package/packages/core/src/system/skills/analyzeDocument.ts +0 -117
  154. package/packages/core/src/system/skills/gitManager.ts +0 -84
  155. package/packages/core/src/system/skills/notionWorkspace.ts +0 -78
  156. package/packages/core/src/system/skills/xManager.ts +0 -76
  157. package/packages/dashboard/dist/assets/index-Czxksiao.js +0 -18
  158. package/packages/dashboard/dist/assets/index-DK2sTU47.css +0 -1
  159. /package/packages/core/src/{gateway → channels}/discordAdapter.ts +0 -0
@@ -6,151 +6,84 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.logger = void 0;
7
7
  exports.processOsIntent = processOsIntent;
8
8
  exports.processOsIntentStream = processOsIntentStream;
9
- const fs_1 = __importDefault(require("fs"));
10
9
  const parser_1 = require("../config/parser");
11
10
  const logger_1 = require("../memory/logger");
12
11
  const tracker_1 = require("../gateway/tracker");
13
- const episodic_1 = require("../memory/episodic");
14
12
  const skillManager_1 = require("../utils/skillManager");
15
- const cognitiveManager_1 = require("../cognitive/cognitiveManager");
16
13
  const reasoningScratchpad_1 = require("./reasoningScratchpad");
17
14
  const contextSummarizer_1 = require("../utils/contextSummarizer");
18
- const EXECUTION_DISCIPLINE = `
19
- <tool_persistence>
20
- Use tools whenever they can increase the accuracy, completeness, or factual correctness of your response.
21
- Do NOT stop early if another tool call would materially improve the result.
22
- Continue using tools until the task is completely finished and verified.
23
- </tool_persistence>
24
-
25
- <mandatory_tool_use>
26
- NEVER answer the following using only your internal memory — ALWAYS use the relevant tool:
27
- - Arithmetic, math, calculations
28
- - System State: OS version, RAM, processes
29
- - File contents, file sizes
30
- - Real-world current events
31
- </mandatory_tool_use>
32
-
33
- <web_search_accuracy>
34
- When using the search_web tool to look up news, current events, or factual data:
35
- 1. NEVER pass casual, conversational, or highly localized queries directly to the tool (e.g. do not pass "hasil piala dunia tadi pagi").
36
- 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").
37
- 3. Use depth: 2 (deep research) for anything that requires high factual accuracy, such as sports scores, news, or complex topics.
38
- </web_search_accuracy>
39
-
40
- <act_dont_ask>
41
- When a user's request has a clear, standard interpretation, take immediate ACTION instead of asking for clarification.
42
- NEVER show a command as a markdown code block and wait. CALL the tool directly.
43
- NEVER ask "do you want me to run this?" — just run it.
44
- NEVER say "you need to run this yourself" — you have direct shell access.
45
- If a command requires sudo and may need a password, just run it and report what happens.
46
- Only report failure AFTER actually attempting the tool call and receiving an error.
47
- </act_dont_ask>
48
-
49
- <anti_hallucination_execution>
50
- 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.
51
- Writing a code block does NOT execute anything. It is a lie to the user.
52
- If you write \`\`\`bash\nsudo apt install steam\n\`\`\` instead of calling run_terminal_command, you are hallucinating execution.
53
- The ONLY way to run a command is to emit a proper tool_call for run_terminal_command.
54
- If the tool is available, USE IT. Do not simulate or describe running it.
55
- </anti_hallucination_execution>
56
-
57
- <task_completion>
58
- 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.
59
- NEVER fabricate, hallucinate, or forge tool outputs.
60
- </task_completion>
61
-
62
- <self_correction>
63
- 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.
64
- Ask yourself: "Is my answer based on absolute facts, or circumstantial evidence (e.g., guessing a registration date based on a video upload date)?"
65
- 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.
66
- </self_correction>
67
- `;
15
+ const promptBuilder_1 = require("./promptBuilder");
68
16
  const registry_1 = require("../plugin/registry");
69
- const paths_1 = require("../config/paths");
70
17
  const picocolors_1 = __importDefault(require("picocolors"));
71
- exports.logger = new logger_1.Logger();
72
- const llmUtils_1 = require("../utils/llmUtils");
73
- async function getSystemPrompt(context = 'os', userInput = '') {
74
- const config = (0, parser_1.loadConfig)();
75
- const currentDateTime = new Date().toLocaleString('en-US');
76
- let basePrompt = `You are Nyxora's OS Agent (System & Automation Specialist).
77
- The current real-world date and time is: ${currentDateTime}.
78
-
79
- 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.
80
-
81
- Reason internally. Never reveal private reasoning. Provide only concise conclusions, assumptions, and actionable steps.
82
-
83
- [OS EXECUTION WORKFLOW]
84
- CRITICAL RULE 1: NEVER expose internal JSON tool calls. Explain the outcome naturally.
85
- 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.
86
- 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.
87
- 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.
88
- CRITICAL RULE 5: TOOL CONFIDENCE. NEVER fabricate file contents or command outputs.
89
-
90
- [SUDO & PACKAGE INSTALL STRATEGY]
91
- This tool runs in a NON-INTERACTIVE shell (no TTY). Therefore:
92
- - ALWAYS prefix apt/apt-get commands with: DEBIAN_FRONTEND=noninteractive
93
- - ALWAYS use the -y flag for package installations to auto-confirm.
94
- - If a command fails with "sudo: a password is required" or similar, DO NOT promise to retry without actually retrying. Instead:
95
- 1. First retry with: echo 'USER_PASSWORD' | sudo -S <command> — but since you don't know the password, skip this.
96
- 2. Instead, try running the command WITHOUT sudo if possible (e.g. for user-space tools).
97
- 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.
98
- - NEVER promise to retry ("let me try again", "I'll run it again", etc.) without immediately making another tool_call in the same response.
99
-
100
- ${EXECUTION_DISCIPLINE}
101
- `;
102
- // Inject Active Cognitive Skills
103
- const activeSOP = cognitiveManager_1.cognitiveManager.loadActiveCognitiveSkills(userInput);
104
- if (activeSOP) {
105
- basePrompt += `\n\n[ACTIVE COGNITIVE SKILLS]\n${activeSOP}\n`;
106
- }
107
- // Inject Episodic Memories via Python RAG
108
- try {
109
- const ragRes = await fetch('http://127.0.0.1:8000/memory/rag', {
110
- method: 'POST',
111
- headers: { 'Content-Type': 'application/json' },
112
- body: JSON.stringify({ query: userInput, top_k: 5 })
113
- });
114
- if (ragRes.ok) {
115
- const ragData = await ragRes.json();
116
- if (ragData.memories && ragData.memories.length > 0) {
117
- basePrompt += `\n\n--- EPISODIC MEMORIES (SMART SUGGESTIONS) ---\n`;
118
- ragData.memories.forEach((mem) => {
119
- basePrompt += `- ${mem}\n`;
120
- });
18
+ // --- REGISTER LIFECYCLE HOOKS ---
19
+ registry_1.pluginManager.registerHook({
20
+ name: 'ReasoningGate',
21
+ beforeToolCall: async (toolName, args, context) => {
22
+ // FIX: Use actual Nyxora tool names (not legacy names)
23
+ const toolsRequiringReasoning = ['run_terminal_command', 'write_local_file', 'edit_local_file', 'execute_script'];
24
+ if (toolsRequiringReasoning.includes(toolName)) {
25
+ const responseMessage = context.responseMessage || {};
26
+ const hasThinkingTag = /<(think|thought|thinking|reasoning|analysis|reflection)>[\s\S]*?<\/\1>/i.test(responseMessage.content || '');
27
+ const hasNativeReasoning = !!responseMessage.reasoning_content;
28
+ if (!hasThinkingTag && !hasNativeReasoning) {
29
+ const msg = `[System Error] BLOCKED BY REASONING GATE: You MUST output a <think>...</think> block to plan your actions BEFORE calling the '${toolName}' tool. Please rethink and try again.`;
30
+ console.log(picocolors_1.default.red(`[ Blocked] Tool ${toolName} blocked by Reasoning Gate.`));
31
+ return { block: true, reason: msg };
121
32
  }
122
33
  }
123
34
  }
124
- catch (e) {
125
- // Fallback or ignore if Python ML engine is down
126
- }
127
- // Inject User Information & Personas from user.md
128
- try {
129
- const userMdPath = (0, paths_1.getPath)('user.md');
130
- if (fs_1.default.existsSync(userMdPath)) {
131
- const userInstructions = fs_1.default.readFileSync(userMdPath, 'utf8');
132
- basePrompt += `\n\n--- USER INFORMATION & PREFERENCES ---\n${userInstructions}\n`;
35
+ });
36
+ registry_1.pluginManager.registerHook({
37
+ name: 'Web3FastReturn',
38
+ afterToolCall: async (toolName, args, result, context) => {
39
+ // FIX: Only financial Web3 transactions need fast-return (to show approval popup ASAP).
40
+ // send_telegram_file is NOT a financial transaction — removed from this list.
41
+ const fastReturnTools = ['transfer_token', 'transfer_native', 'swap_token', 'bridge_token', 'mint_nft', 'custom_tx', 'revoke_approval', 'supply_aave', 'deposit_yield_vault', 'provide_liquidity_v3'];
42
+ if (fastReturnTools.includes(toolName)) {
43
+ return { terminate: true };
133
44
  }
134
45
  }
135
- catch (e) {
136
- // Ignore error
137
- }
138
- // HIGHEST PRIORITY: Inject observed user communication style (NyxDaemon)
46
+ });
47
+ // --- END LIFECYCLE HOOKS ---
48
+ exports.logger = new logger_1.Logger();
49
+ // Helper to trigger background review async
50
+ const triggerBackgroundReview = async (sessionId) => {
139
51
  try {
140
- const strongPersonas = episodic_1.episodicDB.getStrongPersonas(0.5);
141
- if (strongPersonas.length > 0) {
142
- basePrompt += `\n\n--- ⚡ OVERRIDE: USER COMMUNICATION STYLE (HIGHEST PRIORITY — OVERRIDES ALL RULES ABOVE) ---\n`;
143
- 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`;
144
- strongPersonas.forEach(p => {
145
- const label = p.category ? `[${p.category.toUpperCase()}]` : '[PREFERENCE]';
146
- basePrompt += `${label} ${p.trait}\n`;
147
- });
148
- }
52
+ const history = exports.logger.getHistory(sessionId, 30);
53
+ fetch('http://127.0.0.1:8000/cognitive/review', {
54
+ method: 'POST',
55
+ headers: { 'Content-Type': 'application/json' },
56
+ body: JSON.stringify({
57
+ messages: history,
58
+ session_id: sessionId || 'default',
59
+ trigger: 'turn_end'
60
+ })
61
+ }).catch(() => { });
149
62
  }
150
63
  catch (e) {
151
- // Ignore
64
+ // silently fail
152
65
  }
153
- return basePrompt;
66
+ };
67
+ const llmUtils_1 = require("../utils/llmUtils");
68
+ async function getSystemPrompt(context = 'os', userInput = '') {
69
+ const config = (0, parser_1.loadConfig)();
70
+ // Safely deduce model family from config
71
+ const provider = (config?.llm?.provider || '').toLowerCase();
72
+ let modelFamily = 'unknown';
73
+ if (provider.includes('openai'))
74
+ modelFamily = 'openai';
75
+ else if (provider.includes('gemini') || provider.includes('google'))
76
+ modelFamily = 'google';
77
+ else if (provider.includes('anthropic') || provider.includes('claude'))
78
+ modelFamily = 'anthropic';
79
+ else if (provider.includes('grok') || provider.includes('xai'))
80
+ modelFamily = 'grok';
81
+ return await promptBuilder_1.promptBuilder.buildSystemPrompt({
82
+ agentType: context,
83
+ userInput,
84
+ config,
85
+ modelFamily
86
+ });
154
87
  }
155
88
  async function processOsIntent(input, role = 'user', onProgress, sessionId) {
156
89
  const config = (0, parser_1.loadConfig)();
@@ -180,8 +113,20 @@ CRITICAL INSTRUCTIONS:
180
113
  4. Base your new answer strictly on the NEW tool results.`
181
114
  }, sessionId);
182
115
  }
116
+ // FIX: Lazy-init guard — ensure plugins are always initialized before use.
117
+ // This handles cases where processOsIntent is called before startServer() completes,
118
+ // e.g., direct Telegram messages arriving before plugin initialization.
119
+ if (registry_1.pluginManager.getPlugins().length === 0) {
120
+ console.warn('[OsAgent] ⚠️ Plugins not initialized! Running lazy initializePlugins()...');
121
+ await (0, registry_1.initializePlugins)();
122
+ }
183
123
  let activeTools = [...registry_1.pluginManager.getAllToolDefinitions()];
184
124
  activeTools = activeTools.filter(t => (0, skillManager_1.isSkillActive)(t.function.name));
125
+ if (activeTools.length === 0) {
126
+ console.error('[OsAgent] ❌ CRITICAL: No active tools found after initialization! Retrying...');
127
+ await (0, registry_1.initializePlugins)();
128
+ activeTools = [...registry_1.pluginManager.getAllToolDefinitions()].filter(t => (0, skillManager_1.isSkillActive)(t.function.name));
129
+ }
185
130
  // P1: Init reasoning scratchpad for this request
186
131
  const scratchpad = new reasoningScratchpad_1.ReasoningScratchpad();
187
132
  // P3: Build system prompt ONCE per request — not per turn
@@ -213,7 +158,8 @@ CRITICAL INSTRUCTIONS:
213
158
  model: config.llm.model,
214
159
  temperature: config.llm.temperature,
215
160
  messages: messages,
216
- tools: activeTools
161
+ tools: activeTools,
162
+ reasoning_effort: (!config.llm.reasoning_effort || config.llm.reasoning_effort === 'none') ? undefined : config.llm.reasoning_effort
217
163
  });
218
164
  });
219
165
  const responseMessage = response.message;
@@ -232,41 +178,16 @@ CRITICAL INSTRUCTIONS:
232
178
  tool_calls: responseMessage.tool_calls,
233
179
  }, sessionId);
234
180
  if (!responseMessage.tool_calls || responseMessage.tool_calls.length === 0) {
235
- // --- CRITIC PASS (Self-Improvement) ---
236
- const isLongResponse = (cleanedContent?.length ?? 0) > 100;
237
- if (isLongResponse && !criticHasFired) {
238
- criticHasFired = true;
239
- try {
240
- const criticRes = await fetch('http://127.0.0.1:8000/cognitive/critic', {
241
- method: 'POST',
242
- headers: { 'Content-Type': 'application/json' },
243
- body: JSON.stringify({ user_input: input, draft_answer: cleanedContent, current_utc_datetime: new Date().toISOString() })
244
- });
245
- if (criticRes.ok) {
246
- const evaluation = await criticRes.json();
247
- if (evaluation.needs_revision) {
248
- console.log(picocolors_1.default.cyan(`[🧠 Critic] Revision needed. Confidence: ${evaluation.factual_confidence?.toFixed(2)}. Completeness: ${evaluation.completeness?.toFixed(2)}. Re-generating...`));
249
- exports.logger.addEntry({
250
- role: 'system',
251
- 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.`
252
- }, sessionId);
253
- continue; // Loop kembali ke Generator untuk revisi
254
- }
255
- else {
256
- console.log(picocolors_1.default.green(`[🧠 Critic] Passed. Confidence: ${evaluation.factual_confidence?.toFixed(2)}, Completeness: ${evaluation.completeness?.toFixed(2)}.`));
257
- }
258
- }
259
- }
260
- catch {
261
- // Python ML Engine tidak aktif — skip Critic, lanjut seperti biasa
262
- }
263
- }
264
- // --- END CRITIC PASS ---
181
+ // --- CRITIC PASS REMOVED ---
182
+ // The new PromptBuilder handles robust reasoning. Post-generation critic
183
+ // causes aggressive loops and UI artifacts.
184
+ triggerBackgroundReview(sessionId);
265
185
  return cleanedContent || 'No response generated.';
266
186
  }
267
187
  let canFastReturnAll = true;
268
188
  let accumulatedResults = [];
269
189
  // Enabled fastReturnTools to eliminate 2nd LLM latency for transaction popups
190
+ // FIX: Removed send_telegram_file — not a financial transaction
270
191
  const fastReturnTools = [
271
192
  'transfer_token', 'transfer_native', 'swap_token', 'bridge_token',
272
193
  'mint_nft', 'custom_tx', 'revoke_approval', 'supply_aave',
@@ -277,9 +198,32 @@ CRITICAL INSTRUCTIONS:
277
198
  let result = "";
278
199
  let args = {};
279
200
  const toolName = toolCall.function.name;
201
+ const getToolEmoji = (n) => {
202
+ if (n.includes('file') || n.includes('read') || n.includes('write'))
203
+ return '📄';
204
+ if (n.includes('dir') || n.includes('folder'))
205
+ return '📁';
206
+ if (n.includes('cmd') || n.includes('shell') || n.includes('run'))
207
+ return '🖥️';
208
+ if (n.includes('search') || n.includes('find'))
209
+ return '🔍';
210
+ if (n.includes('git'))
211
+ return '🐙';
212
+ return '⚙️';
213
+ };
214
+ const emoji = getToolEmoji(toolName);
215
+ let argsPreview = "";
216
+ try {
217
+ const parsedArgs = JSON.parse(toolCall.function.arguments || "{}");
218
+ const firstKey = Object.keys(parsedArgs)[0];
219
+ if (firstKey)
220
+ argsPreview = `"${parsedArgs[firstKey]}"`;
221
+ }
222
+ catch (e) { }
223
+ const previewMsg = argsPreview ? `${toolName}: ${argsPreview}` : toolName;
280
224
  console.log(picocolors_1.default.yellow(`[⚡ Tool Execution] AI is calling ${toolName}...`));
281
225
  if (onProgress)
282
- onProgress(`_⚡ Running tool: ${toolName}..._`);
226
+ onProgress(`*${emoji} ${previewMsg}*`);
283
227
  try {
284
228
  let argStr = toolCall.function.arguments;
285
229
  // [Auto-Recovery] Fix common LLM JSON errors (e.g. missing closing brace)
@@ -335,7 +279,8 @@ CRITICAL INSTRUCTIONS:
335
279
  content: result,
336
280
  }, sessionId);
337
281
  accumulatedResults.push(result);
338
- if (!fastReturnTools.includes(toolName)) {
282
+ // FIX: Removed send_telegram_file from fast-return set
283
+ if (!['transfer_token', 'transfer_native', 'swap_token', 'bridge_token', 'mint_nft', 'custom_tx', 'revoke_approval', 'supply_aave', 'deposit_yield_vault', 'provide_liquidity_v3'].includes(toolName)) {
339
284
  canFastReturnAll = false;
340
285
  }
341
286
  }
@@ -352,6 +297,7 @@ CRITICAL INSTRUCTIONS:
352
297
  if (consecutiveToolErrors >= 2) {
353
298
  const errorSummary = `⚠️ Unable to complete this request after multiple attempts.\n${accumulatedResults.join('\n')}`;
354
299
  exports.logger.addEntry({ role: 'assistant', content: errorSummary }, sessionId);
300
+ triggerBackgroundReview(sessionId);
355
301
  return errorSummary;
356
302
  }
357
303
  }
@@ -362,12 +308,14 @@ CRITICAL INSTRUCTIONS:
362
308
  if (canFastReturnAll && accumulatedResults.length > 0) {
363
309
  const finalContent = accumulatedResults.join('\n\n---\n\n');
364
310
  exports.logger.addEntry({ role: 'assistant', content: finalContent }, sessionId);
311
+ triggerBackgroundReview(sessionId);
365
312
  return finalContent;
366
313
  }
367
314
  // Loop continues, sending tool results in the next turn
368
315
  }
369
316
  const maxTurnMsg = "⚠️ Reached maximum interaction limit (10 turns). Please be more specific.";
370
317
  exports.logger.addEntry({ role: 'assistant', content: maxTurnMsg }, sessionId);
318
+ triggerBackgroundReview(sessionId);
371
319
  return maxTurnMsg;
372
320
  }
373
321
  catch (error) {
@@ -408,8 +356,20 @@ CRITICAL INSTRUCTIONS:
408
356
  4. Base your new answer strictly on the NEW tool results.`
409
357
  }, sessionId);
410
358
  }
359
+ // FIX: Lazy-init guard — same as processOsIntent
360
+ if (registry_1.pluginManager.getPlugins().length === 0) {
361
+ console.warn('[OsAgentStream] ⚠️ Plugins not initialized! Running lazy initializePlugins()...');
362
+ await (0, registry_1.initializePlugins)();
363
+ }
411
364
  const pluginTools = registry_1.pluginManager.getAllToolDefinitions();
412
365
  let activeTools = [...pluginTools].filter(t => (0, skillManager_1.isSkillActive)(t.function.name));
366
+ if (activeTools.length === 0) {
367
+ console.error('[OsAgentStream] ❌ CRITICAL: No active tools found after initialization! Retrying...');
368
+ await (0, registry_1.initializePlugins)();
369
+ activeTools = [...registry_1.pluginManager.getAllToolDefinitions()].filter(t => (0, skillManager_1.isSkillActive)(t.function.name));
370
+ }
371
+ // FIX: Cache system prompt ONCE before loop (was being rebuilt every turn — wasteful)
372
+ const cachedSystemPromptStream = await getSystemPrompt('os', input);
413
373
  const { sanitizeHistoryForLLM } = require('../utils/historySanitizer');
414
374
  try {
415
375
  let turnCount = 0;
@@ -420,13 +380,20 @@ CRITICAL INSTRUCTIONS:
420
380
  turnCount++;
421
381
  const currentHistory = exports.logger.getHistory(sessionId);
422
382
  const sanitizedHistory = sanitizeHistoryForLLM(currentHistory, activeTools, config.llm.provider);
383
+ // FIX: Use cached system prompt — no longer rebuilt every turn
423
384
  const messages = [
424
- { role: 'system', content: await getSystemPrompt('os', input) },
385
+ { role: 'system', content: cachedSystemPromptStream },
425
386
  ...sanitizedHistory
426
387
  ];
427
388
  let streamedContent = '';
428
389
  const response = await (0, llmUtils_1.executeWithRetry)(async (client) => {
429
- return await client.stream({ model: config.llm.model, temperature: config.llm.temperature, messages, tools: activeTools }, (chunk) => {
390
+ streamedContent = '';
391
+ // RC#1 FIX: Only clear the Telegram buffer on the FIRST turn.
392
+ // On subsequent turns (after tool calls), the buffer already shows useful
393
+ // progress info. Resetting it causes visible content to disappear.
394
+ if (turnCount === 1)
395
+ onChunk('[CLEAR_STREAM]');
396
+ return await client.stream({ model: config.llm.model, temperature: config.llm.temperature, messages, tools: activeTools, reasoning_effort: (!config.llm.reasoning_effort || config.llm.reasoning_effort === 'none') ? undefined : config.llm.reasoning_effort }, (chunk) => {
430
397
  streamedContent += chunk;
431
398
  onChunk(chunk);
432
399
  });
@@ -440,53 +407,33 @@ CRITICAL INSTRUCTIONS:
440
407
  exports.logger.addEntry({
441
408
  role: 'assistant',
442
409
  content: responseMessage.content || '',
410
+ reasoning_content: responseMessage.reasoning_content,
443
411
  tool_calls: responseMessage.tool_calls,
444
412
  }, sessionId);
445
413
  if (!responseMessage.tool_calls || responseMessage.tool_calls.length === 0) {
446
414
  let finalContent = responseMessage.content || 'No response generated.';
447
415
  finalContent = finalContent.replace(/<(think|thought|thinking|reasoning|analysis|reflection)[\s\S]*?<\/\1>\n?/gi, '').trim();
448
- // --- CRITIC PASS (Self-Improvement) ---
449
- const isLongResponseStream = finalContent.length > 100;
450
- if (isLongResponseStream && !criticHasFiredStream) {
451
- criticHasFiredStream = true;
452
- try {
453
- const criticRes = await fetch('http://127.0.0.1:8000/cognitive/critic', {
454
- method: 'POST',
455
- headers: { 'Content-Type': 'application/json' },
456
- body: JSON.stringify({ user_input: input, draft_answer: finalContent, current_utc_datetime: new Date().toISOString() })
457
- });
458
- if (criticRes.ok) {
459
- const evaluation = await criticRes.json();
460
- if (evaluation.needs_revision) {
461
- console.log(picocolors_1.default.cyan(`[🧠 Critic] Revision needed. Confidence: ${evaluation.factual_confidence?.toFixed(2)}. Completeness: ${evaluation.completeness?.toFixed(2)}. Re-generating...`));
462
- exports.logger.addEntry({
463
- role: 'system',
464
- 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.`
465
- }, sessionId);
466
- continue; // Loop kembali ke Generator untuk revisi
467
- }
468
- else {
469
- console.log(picocolors_1.default.green(`[🧠 Critic] Passed. Confidence: ${evaluation.factual_confidence?.toFixed(2)}, Completeness: ${evaluation.completeness?.toFixed(2)}.`));
470
- }
471
- }
472
- }
473
- catch {
474
- // Python ML Engine tidak aktif — skip Critic, lanjut seperti biasa
475
- }
476
- }
477
- // --- END CRITIC PASS ---
416
+ finalContent = finalContent.replace(/^\s*(?:\*\*)?(?:think|thought|thinking|reasoning|analysis|reflection)(?:\*\*)?\s*?\n[\s\S]*?\n\n/i, '').trim();
417
+ // --- CRITIC PASS REMOVED ---
418
+ // Prevents leaking internal reasoning into the stream and confusing the user.
478
419
  fullResponse = finalContent;
420
+ triggerBackgroundReview(sessionId);
479
421
  break;
480
422
  }
481
- // Tool calls detected — pause stream visually and execute tools
482
- const fastReturnTools = ['transfer_token', 'transfer_native', 'swap_token', 'bridge_token', 'mint_nft', 'custom_tx', 'revoke_approval', 'supply_aave', 'deposit_yield_vault', 'provide_liquidity_v3'];
483
- let canFastReturnAll = true;
423
+ // Tool calls detected — pause stream visually and execute tools concurrently
424
+ // BUG#1 FIX: Signal to Telegram to wipe turn-1 planning text from the buffer.
425
+ // LLM often generates "thinking out loud" text before calling a tool (e.g. "Let me check...").
426
+ // This text should NOT be shown to users. [TOOL_CALL_DETECTED] resets the buffer to a
427
+ // clean progress indicator, hiding the planning text without losing the message handle.
428
+ onChunk('[TOOL_CALL_DETECTED]');
429
+ let shouldFastReturn = false;
484
430
  const accumulatedResults = [];
485
- for (const _toolCall of responseMessage.tool_calls) {
431
+ const promises = responseMessage.tool_calls.map(async (_toolCall) => {
486
432
  const toolCall = _toolCall;
487
433
  const toolName = toolCall.function.name;
488
434
  let result = '';
489
435
  let args = {};
436
+ const context = { sessionId, toolCallId: toolCall.id, responseMessage };
490
437
  console.log(picocolors_1.default.yellow(`[⚡ Tool Execution] AI is calling ${toolName}...`));
491
438
  if (onProgress)
492
439
  onProgress(`_⚡ Running tool: ${toolName}..._`);
@@ -499,17 +446,28 @@ CRITICAL INSTRUCTIONS:
499
446
  catch (parseError) {
500
447
  result = `[System Error] Arguments for ${toolName} must be valid JSON. Error: ${parseError.message}`;
501
448
  exports.logger.addEntry({ role: 'tool', tool_call_id: toolCall.id, content: result }, sessionId);
502
- continue;
449
+ return { toolName, result };
503
450
  }
504
451
  if (!(0, skillManager_1.isSkillActive)(toolName)) {
505
452
  result = `[System Error] Access denied: Skill '${toolName}' is currently disabled.`;
506
453
  exports.logger.addEntry({ role: 'tool', tool_call_id: toolCall.id, content: result }, sessionId);
507
- continue;
454
+ return { toolName, result };
455
+ }
456
+ // --- LIFECYCLE: BEFORE TOOL CALL ---
457
+ const beforeRes = await registry_1.pluginManager.triggerBeforeHooks(toolName, args, context);
458
+ if (beforeRes && beforeRes.block) {
459
+ result = beforeRes.reason || `[System Error] Blocked by hook for ${toolName}`;
460
+ exports.logger.addEntry({ role: 'tool', tool_call_id: toolCall.id, content: result }, sessionId);
461
+ return { toolName, result };
508
462
  }
509
463
  try {
510
- const pluginResult = await registry_1.pluginManager.executeTool(toolName, args, { sessionId });
464
+ const pluginResult = await registry_1.pluginManager.executeTool(toolName, args, context, (partialResult) => {
465
+ // Partial Streaming callback
466
+ if (onProgress)
467
+ onProgress(`_⏳ [${toolName}] ${partialResult}..._`);
468
+ });
511
469
  result = pluginResult !== null ? pluginResult : `Error: Tool ${toolName} is not implemented.`;
512
- if (result.includes('[Security Blocked]') || result.startsWith('Error:')) {
470
+ if (typeof result === 'string' && (result.includes('[Security Blocked]') || result.startsWith('Error:'))) {
513
471
  console.log(picocolors_1.default.red(`[❌ Failed] Tool ${toolName} returned an error or was blocked.`));
514
472
  }
515
473
  else {
@@ -520,16 +478,23 @@ CRITICAL INSTRUCTIONS:
520
478
  result = `Error executing ${toolName}: ${toolError.message}`;
521
479
  console.error(picocolors_1.default.red(`[❌ Error Crash] Execution of ${toolName} failed: ${toolError.message}`));
522
480
  }
481
+ // --- LIFECYCLE: AFTER TOOL CALL ---
482
+ const afterRes = await registry_1.pluginManager.triggerAfterHooks(toolName, args, result, context);
483
+ result = afterRes.content || result;
484
+ if (afterRes.terminate) {
485
+ shouldFastReturn = true;
486
+ }
523
487
  exports.logger.addEntry({ role: 'tool', tool_call_id: toolCall.id, name: toolName, content: result }, sessionId);
524
- accumulatedResults.push(result);
525
- if (!fastReturnTools.includes(toolName))
526
- canFastReturnAll = false;
527
- }
528
- if (canFastReturnAll && accumulatedResults.length > 0) {
488
+ return { toolName, result };
489
+ });
490
+ const results = await Promise.all(promises);
491
+ results.forEach(r => accumulatedResults.push(r.result));
492
+ if (shouldFastReturn && accumulatedResults.length > 0) {
529
493
  const finalContent = accumulatedResults.join('\n\n---\n\n');
530
494
  exports.logger.addEntry({ role: 'assistant', content: finalContent }, sessionId);
531
495
  onChunk(finalContent);
532
496
  fullResponse = finalContent;
497
+ triggerBackgroundReview(sessionId);
533
498
  break;
534
499
  }
535
500
  }
@@ -537,6 +502,7 @@ CRITICAL INSTRUCTIONS:
537
502
  const maxTurnMsg = '⚠️ Reached maximum interaction limit (10 turns). Please be more specific.';
538
503
  exports.logger.addEntry({ role: 'assistant', content: maxTurnMsg }, sessionId);
539
504
  fullResponse = maxTurnMsg;
505
+ triggerBackgroundReview(sessionId);
540
506
  }
541
507
  return fullResponse;
542
508
  }