nyxora 26.6.23 → 26.6.24

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 (56) hide show
  1. package/dist/packages/core/src/agent/cronManager.js +6 -3
  2. package/dist/packages/core/src/agent/llmProvider.js +250 -0
  3. package/dist/packages/core/src/agent/osAgent.js +389 -0
  4. package/dist/packages/core/src/agent/reasoning.js +155 -433
  5. package/dist/packages/core/src/agent/web3Agent.js +400 -0
  6. package/dist/packages/core/src/gateway/doctor.js +32 -4
  7. package/dist/packages/core/src/gateway/setup.js +19 -7
  8. package/dist/packages/core/src/gateway/telegram.js +40 -52
  9. package/dist/packages/core/src/gateway/tracker.js +44 -1
  10. package/dist/packages/core/src/system/skills/searchWeb.js +26 -3
  11. package/dist/packages/core/src/system/skills/summarizeText.js +3 -3
  12. package/dist/packages/core/src/utils/historySanitizer.js +36 -0
  13. package/dist/packages/core/src/utils/skillManager.js +11 -2
  14. package/dist/packages/core/src/web3/aggregator/defiRouter.js +2 -0
  15. package/dist/packages/core/src/web3/skills/bridgeToken.js +2 -0
  16. package/dist/packages/core/src/web3/skills/checkPortfolio.js +7 -6
  17. package/dist/packages/core/src/web3/skills/checkRegistryStatus.js +5 -5
  18. package/dist/packages/core/src/web3/skills/checkSecurity.js +1 -1
  19. package/dist/packages/core/src/web3/skills/getPrice.js +1 -1
  20. package/dist/packages/core/src/web3/skills/getTxHistory.js +2 -2
  21. package/dist/packages/core/src/web3/skills/marketAnalysis.js +1 -1
  22. package/dist/packages/core/src/web3/skills/nativeOpBridge.js +4 -3
  23. package/dist/packages/core/src/web3/skills/provideLiquidity.js +1 -1
  24. package/dist/packages/core/src/web3/utils/vaultClient.js +2 -2
  25. package/dist/packages/policy/src/server.js +30 -14
  26. package/package.json +18 -8
  27. package/packages/core/package.json +4 -6
  28. package/packages/core/src/agent/cronManager.ts +6 -4
  29. package/packages/core/src/agent/llmProvider.ts +272 -0
  30. package/packages/core/src/agent/osAgent.ts +445 -0
  31. package/packages/core/src/agent/reasoning.ts +185 -531
  32. package/packages/core/src/agent/web3Agent.ts +483 -0
  33. package/packages/core/src/config/parser.ts +1 -0
  34. package/packages/core/src/gateway/doctor.ts +32 -4
  35. package/packages/core/src/gateway/setup.ts +18 -7
  36. package/packages/core/src/gateway/telegram.ts +43 -54
  37. package/packages/core/src/gateway/tracker.ts +10 -1
  38. package/packages/core/src/system/skills/searchWeb.ts +27 -3
  39. package/packages/core/src/system/skills/summarizeText.ts +4 -4
  40. package/packages/core/src/utils/historySanitizer.ts +38 -0
  41. package/packages/core/src/utils/skillManager.ts +11 -2
  42. package/packages/core/src/web3/aggregator/defiRouter.ts +6 -4
  43. package/packages/core/src/web3/skills/bridgeToken.ts +2 -0
  44. package/packages/core/src/web3/skills/checkPortfolio.ts +7 -6
  45. package/packages/core/src/web3/skills/checkRegistryStatus.ts +5 -6
  46. package/packages/core/src/web3/skills/checkSecurity.ts +1 -1
  47. package/packages/core/src/web3/skills/getPrice.ts +1 -1
  48. package/packages/core/src/web3/skills/getTxHistory.ts +2 -2
  49. package/packages/core/src/web3/skills/marketAnalysis.ts +1 -1
  50. package/packages/core/src/web3/skills/nativeOpBridge.ts +4 -3
  51. package/packages/core/src/web3/skills/provideLiquidity.ts +1 -1
  52. package/packages/core/src/web3/utils/vaultClient.ts +2 -2
  53. package/packages/dashboard/dist/assets/{index-CmWZofn_.js → index-BLMS9VtQ.js} +1 -1
  54. package/packages/dashboard/dist/index.html +1 -1
  55. package/packages/policy/package.json +2 -3
  56. package/packages/policy/src/server.ts +33 -13
@@ -37,7 +37,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.cronManager = void 0;
40
- const cron = __importStar(require("node-cron"));
40
+ const croner_1 = require("croner");
41
41
  const parser_1 = require("../config/parser");
42
42
  const telegram_1 = require("../gateway/telegram");
43
43
  const crypto_1 = require("crypto");
@@ -47,10 +47,13 @@ class CronManager {
47
47
  addJob(expression, prompt) {
48
48
  const id = (0, crypto_1.randomUUID)();
49
49
  // Validate expression
50
- if (!cron.validate(expression)) {
50
+ try {
51
+ new croner_1.Cron(expression);
52
+ }
53
+ catch (e) {
51
54
  throw new Error(`Invalid cron expression: ${expression}`);
52
55
  }
53
- const task = cron.schedule(expression, async () => {
56
+ const task = new croner_1.Cron(expression, async () => {
54
57
  console.log(picocolors_1.default.cyan(`[Cron] Executing job ${id}: "${prompt}"`));
55
58
  try {
56
59
  // Dynamically import processUserInput to avoid circular dependencies
@@ -0,0 +1,250 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GeminiAdapter = exports.AnthropicAdapter = exports.OpenAIAdapter = void 0;
4
+ const genai_1 = require("@google/genai");
5
+ class OpenAIAdapter {
6
+ client;
7
+ constructor(client) {
8
+ this.client = client;
9
+ }
10
+ async chat(request) {
11
+ const response = await this.client.chat.completions.create(request);
12
+ return {
13
+ message: {
14
+ content: response.choices[0].message.content,
15
+ tool_calls: response.choices[0].message.tool_calls
16
+ }
17
+ };
18
+ }
19
+ }
20
+ exports.OpenAIAdapter = OpenAIAdapter;
21
+ class AnthropicAdapter {
22
+ client;
23
+ constructor(client) {
24
+ this.client = client;
25
+ }
26
+ async chat(request) {
27
+ let systemPrompt = '';
28
+ const anthropicMessages = [];
29
+ for (const m of request.messages) {
30
+ if (m.role === 'system') {
31
+ systemPrompt = m.content;
32
+ continue;
33
+ }
34
+ if (m.role === 'user') {
35
+ anthropicMessages.push({ role: 'user', content: m.content });
36
+ }
37
+ else if (m.role === 'assistant') {
38
+ const blocks = [];
39
+ if (m.content)
40
+ blocks.push({ type: 'text', text: m.content });
41
+ if (m.tool_calls) {
42
+ m.tool_calls.forEach((tc) => {
43
+ try {
44
+ blocks.push({
45
+ type: 'tool_use',
46
+ id: tc.id,
47
+ name: tc.function.name,
48
+ input: JSON.parse(tc.function.arguments)
49
+ });
50
+ }
51
+ catch (e) { }
52
+ });
53
+ }
54
+ anthropicMessages.push({ role: 'assistant', content: blocks.length > 0 ? blocks : m.content });
55
+ }
56
+ else if (m.role === 'tool') {
57
+ anthropicMessages.push({
58
+ role: 'user',
59
+ content: [
60
+ {
61
+ type: 'tool_result',
62
+ tool_use_id: m.tool_call_id,
63
+ content: m.content
64
+ }
65
+ ]
66
+ });
67
+ }
68
+ }
69
+ // Merge consecutive roles (Anthropic strictly requires alternating user/assistant)
70
+ const mergedAnthropic = [];
71
+ for (const m of anthropicMessages) {
72
+ const last = mergedAnthropic[mergedAnthropic.length - 1];
73
+ if (last && last.role === m.role) {
74
+ if (Array.isArray(last.content) && Array.isArray(m.content)) {
75
+ last.content.push(...m.content);
76
+ }
77
+ else if (typeof last.content === 'string' && typeof m.content === 'string') {
78
+ last.content += '\n\n' + m.content;
79
+ }
80
+ else if (Array.isArray(last.content) && typeof m.content === 'string') {
81
+ last.content.push({ type: 'text', text: m.content });
82
+ }
83
+ else if (typeof last.content === 'string' && Array.isArray(m.content)) {
84
+ last.content = [{ type: 'text', text: last.content }, ...m.content];
85
+ }
86
+ }
87
+ else {
88
+ mergedAnthropic.push(m);
89
+ }
90
+ }
91
+ let anthropicTools = undefined;
92
+ if (request.tools) {
93
+ anthropicTools = request.tools.map(t => ({
94
+ name: t.function.name,
95
+ description: t.function.description,
96
+ input_schema: t.function.parameters
97
+ }));
98
+ }
99
+ const response = await this.client.messages.create({
100
+ model: request.model,
101
+ system: systemPrompt,
102
+ messages: mergedAnthropic,
103
+ tools: anthropicTools,
104
+ temperature: request.temperature,
105
+ max_tokens: request.max_tokens || 4096
106
+ });
107
+ let contentStr = null;
108
+ let toolCalls = [];
109
+ for (const block of response.content) {
110
+ if (block.type === 'text') {
111
+ contentStr = (contentStr || '') + block.text;
112
+ }
113
+ else if (block.type === 'tool_use') {
114
+ toolCalls.push({
115
+ id: block.id,
116
+ type: 'function',
117
+ function: {
118
+ name: block.name,
119
+ arguments: JSON.stringify(block.input)
120
+ }
121
+ });
122
+ }
123
+ }
124
+ return {
125
+ message: {
126
+ content: contentStr,
127
+ tool_calls: toolCalls.length > 0 ? toolCalls : undefined
128
+ }
129
+ };
130
+ }
131
+ }
132
+ exports.AnthropicAdapter = AnthropicAdapter;
133
+ class GeminiAdapter {
134
+ client;
135
+ constructor(client) {
136
+ this.client = client;
137
+ }
138
+ async chat(request) {
139
+ let systemInstruction = '';
140
+ const rawGemini = [];
141
+ for (const m of request.messages) {
142
+ if (m.role === 'system') {
143
+ systemInstruction = m.content;
144
+ continue;
145
+ }
146
+ if (m.role === 'user') {
147
+ rawGemini.push({ role: 'user', parts: [{ text: m.content }] });
148
+ }
149
+ else if (m.role === 'assistant') {
150
+ const parts = [];
151
+ if (m.content)
152
+ parts.push({ text: m.content });
153
+ if (m.tool_calls) {
154
+ m.tool_calls.forEach((tc) => {
155
+ try {
156
+ parts.push({
157
+ functionCall: {
158
+ name: tc.function.name,
159
+ args: JSON.parse(tc.function.arguments)
160
+ }
161
+ });
162
+ }
163
+ catch (e) { }
164
+ });
165
+ }
166
+ rawGemini.push({ role: 'model', parts: parts });
167
+ }
168
+ else if (m.role === 'tool') {
169
+ rawGemini.push({
170
+ role: 'user',
171
+ parts: [{
172
+ functionResponse: {
173
+ name: m.name || 'unknown_tool',
174
+ response: { result: m.content }
175
+ }
176
+ }]
177
+ });
178
+ }
179
+ }
180
+ const geminiMessages = [];
181
+ for (const m of rawGemini) {
182
+ const last = geminiMessages[geminiMessages.length - 1];
183
+ if (last && last.role === m.role) {
184
+ last.parts.push(...m.parts);
185
+ }
186
+ else {
187
+ geminiMessages.push(m);
188
+ }
189
+ }
190
+ let tools = undefined;
191
+ if (request.tools) {
192
+ tools = [{
193
+ functionDeclarations: request.tools.map(t => ({
194
+ name: t.function.name,
195
+ description: t.function.description,
196
+ parameters: t.function.parameters
197
+ }))
198
+ }];
199
+ }
200
+ const response = await this.client.models.generateContent({
201
+ model: request.model,
202
+ contents: geminiMessages,
203
+ config: {
204
+ systemInstruction: systemInstruction,
205
+ tools: tools,
206
+ temperature: request.temperature,
207
+ safetySettings: [
208
+ { category: genai_1.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: genai_1.HarmBlockThreshold.BLOCK_NONE },
209
+ { category: genai_1.HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: genai_1.HarmBlockThreshold.BLOCK_NONE },
210
+ { category: genai_1.HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: genai_1.HarmBlockThreshold.BLOCK_NONE },
211
+ { category: genai_1.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: genai_1.HarmBlockThreshold.BLOCK_NONE }
212
+ ]
213
+ }
214
+ });
215
+ let contentStr = null;
216
+ let toolCalls = [];
217
+ if (response.candidates && response.candidates.length > 0) {
218
+ const candidate = response.candidates[0];
219
+ // Log finish reason for debugging safety blocks
220
+ if (candidate.finishReason && candidate.finishReason !== 'STOP') {
221
+ console.warn(`[LLM] Gemini API returned finishReason: ${candidate.finishReason}`);
222
+ }
223
+ if (candidate.content && candidate.content.parts) {
224
+ const parts = candidate.content.parts;
225
+ for (const part of parts) {
226
+ if (part.text) {
227
+ contentStr = (contentStr || '') + part.text;
228
+ }
229
+ else if (part.functionCall) {
230
+ toolCalls.push({
231
+ id: `call_${Math.random().toString(36).substring(7)}`,
232
+ type: 'function',
233
+ function: {
234
+ name: part.functionCall.name,
235
+ arguments: JSON.stringify(part.functionCall.args)
236
+ }
237
+ });
238
+ }
239
+ }
240
+ }
241
+ }
242
+ return {
243
+ message: {
244
+ content: contentStr,
245
+ tool_calls: toolCalls.length > 0 ? toolCalls : undefined
246
+ }
247
+ };
248
+ }
249
+ }
250
+ exports.GeminiAdapter = GeminiAdapter;
@@ -0,0 +1,389 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.logger = void 0;
7
+ exports.getOpenAI = getOpenAI;
8
+ exports.processOsIntent = processOsIntent;
9
+ const openai_1 = require("openai");
10
+ const parser_1 = require("../config/parser");
11
+ const logger_1 = require("../memory/logger");
12
+ const tracker_1 = require("../gateway/tracker");
13
+ const episodic_1 = require("../memory/episodic");
14
+ const skillManager_1 = require("../utils/skillManager");
15
+ const updateProfile_1 = require("./updateProfile");
16
+ const updateIdentity_1 = require("./updateIdentity");
17
+ const updateSecurityPolicy_1 = require("../system/skills/updateSecurityPolicy");
18
+ const analyzeDocument_1 = require("../system/skills/analyzeDocument");
19
+ const readFile_1 = require("../system/skills/readFile");
20
+ const writeFile_1 = require("../system/skills/writeFile");
21
+ const generateExcel_1 = require("../system/skills/generateExcel");
22
+ const executeShell_1 = require("../system/skills/executeShell");
23
+ const browseWeb_1 = require("../system/skills/browseWeb");
24
+ const searchWeb_1 = require("../system/skills/searchWeb");
25
+ const editFile_1 = require("../system/skills/editFile");
26
+ const gitManager_1 = require("../system/skills/gitManager");
27
+ const xManager_1 = require("../system/skills/xManager");
28
+ const notionWorkspace_1 = require("../system/skills/notionWorkspace");
29
+ const audioTranscribe_1 = require("../system/skills/audioTranscribe");
30
+ const summarizeText_1 = require("../system/skills/summarizeText");
31
+ const scheduleTask_1 = require("../system/skills/scheduleTask");
32
+ const cancelTask_1 = require("../system/skills/cancelTask");
33
+ const googleWorkspace_1 = require("../system/skills/googleWorkspace");
34
+ const picocolors_1 = __importDefault(require("picocolors"));
35
+ exports.logger = new logger_1.Logger();
36
+ const PROVIDER_CONFIGS = {
37
+ ollama: { baseURL: process.env.OLLAMA_BASE_URL ? `${process.env.OLLAMA_BASE_URL}/v1` : 'http://localhost:11434/v1', requiresApiKey: false },
38
+ gemini: { baseURL: 'https://generativelanguage.googleapis.com/v1beta/openai/', requiresApiKey: true },
39
+ openrouter: { baseURL: 'https://openrouter.ai/api/v1', requiresApiKey: true },
40
+ groq: { baseURL: 'https://api.groq.com/openai/v1', requiresApiKey: true },
41
+ mistral: { baseURL: 'https://api.mistral.ai/v1', requiresApiKey: true },
42
+ xai: { baseURL: 'https://api.x.ai/v1', requiresApiKey: true },
43
+ deepseek: { baseURL: 'https://api.deepseek.com', requiresApiKey: true },
44
+ openai: { requiresApiKey: true }
45
+ };
46
+ async function getOpenAI() {
47
+ const config = (0, parser_1.loadConfig)();
48
+ const vaultKeys = await (0, parser_1.loadApiKeys)();
49
+ const providerName = config.llm.provider || 'openai';
50
+ const providerConf = PROVIDER_CONFIGS[providerName] || PROVIDER_CONFIGS['openai'];
51
+ let apiKey = 'local';
52
+ if (providerConf.requiresApiKey) {
53
+ apiKey = '';
54
+ const keyName = `${providerName}_key`;
55
+ apiKey = vaultKeys[keyName] || config.credentials?.[keyName] || '';
56
+ if (!apiKey) {
57
+ throw new Error(`[Security] No API Key found for ${providerName} in OS Keyring. Please run 'nyxora set-key ${providerName} <key>' or 'nyxora setup'.`);
58
+ }
59
+ console.log(`[LLM] Using API Key securely unlocked from OS Keyring vault.`);
60
+ }
61
+ return new openai_1.OpenAI({
62
+ baseURL: providerConf.baseURL,
63
+ apiKey: apiKey,
64
+ timeout: 120 * 1000,
65
+ maxRetries: 0
66
+ });
67
+ }
68
+ async function executeWithRetry(requestBuilder, maxRetries = 3) {
69
+ let retries = 0;
70
+ while (retries <= maxRetries) {
71
+ try {
72
+ const client = await getOpenAI();
73
+ return await requestBuilder(client);
74
+ }
75
+ catch (error) {
76
+ const status = error?.status || error?.response?.status;
77
+ // 401 Unauthorized or 400 Bad Request - don't retry, it's fatal
78
+ if (status === 401 || status === 400) {
79
+ console.error(`[LLM] Fatal Error ${status}: ${error.message}. Aborting.`);
80
+ throw error;
81
+ }
82
+ // 429 Rate Limit - rotate provider/key immediately and retry
83
+ if (status === 429) {
84
+ console.warn(`[LLM] Rate Limit (429) hit. Rotating key...`);
85
+ // getOpenAI() automatically rotates to next key if available
86
+ retries++;
87
+ if (retries > maxRetries)
88
+ throw error;
89
+ continue; // Try next key immediately
90
+ }
91
+ // 500, 502, 503, Timeout, Network error - Exponential Backoff
92
+ retries++;
93
+ if (retries > maxRetries) {
94
+ console.error(`[LLM] Max retries reached.`);
95
+ throw error;
96
+ }
97
+ const delayMs = Math.pow(2, retries) * 1000; // 2s, 4s, 8s
98
+ console.warn(`[LLM] API Error (${status || error.message}). Retrying in ${delayMs}ms...`);
99
+ await new Promise(resolve => setTimeout(resolve, delayMs));
100
+ }
101
+ }
102
+ }
103
+ function getSystemPrompt(context = 'os') {
104
+ const config = (0, parser_1.loadConfig)();
105
+ const currentDateTime = new Date().toLocaleString('id-ID', { timeZone: 'Asia/Jakarta' });
106
+ let basePrompt = `You are Nyxora's OS Agent (System & Automation Specialist).
107
+ The current real-world date and time is: ${currentDateTime}.
108
+
109
+ Reason internally. Never reveal private reasoning. Provide only concise conclusions, assumptions, and actionable steps.
110
+
111
+ [OS EXECUTION WORKFLOW]
112
+ CRITICAL RULE 1: NEVER expose internal JSON tool calls. Explain the outcome naturally.
113
+ CRITICAL RULE 2: STRICT LANGUAGE MATCHING. Reply in the exact same language as the user's LATEST prompt.
114
+ 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.
115
+ 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.
116
+ CRITICAL RULE 5: TOOL CONFIDENCE. NEVER fabricate file contents or command outputs.`;
117
+ // Inject Episodic Memories
118
+ try {
119
+ const recentMemories = episodic_1.episodicDB.getMemories().slice(0, 10);
120
+ if (recentMemories.length > 0) {
121
+ basePrompt += `
122
+
123
+ --- EPISODIC MEMORIES (SMART SUGGESTIONS) ---
124
+ `;
125
+ recentMemories.forEach(mem => {
126
+ basePrompt += `- [${mem.category.toUpperCase()}] ${mem.fact} (Confidence: ${(mem.confidence * 100).toFixed(0)}%)
127
+ `;
128
+ });
129
+ }
130
+ }
131
+ catch (error) { }
132
+ return basePrompt;
133
+ }
134
+ async function processOsIntent(input, role = 'user', onProgress, sessionId) {
135
+ const config = (0, parser_1.loadConfig)();
136
+ // Add input to memory
137
+ exports.logger.addEntry({ role, content: input }, sessionId);
138
+ const history = exports.logger.getHistory(sessionId);
139
+ // Format messages for OpenAI
140
+ let activeTools = [];
141
+ const SYSTEM_TOOLS = [updateProfile_1.updateProfileToolDefinition, updateIdentity_1.updateIdentityToolDefinition, updateSecurityPolicy_1.updateSecurityPolicyToolDefinition, analyzeDocument_1.analyzeDocumentToolDefinition, readFile_1.readLocalFileToolDefinition, writeFile_1.writeLocalFileToolDefinition, generateExcel_1.generateExcelToolDefinition, executeShell_1.runTerminalCommandToolDefinition, browseWeb_1.browseWebsiteToolDefinition, searchWeb_1.searchWebToolDefinition, editFile_1.editLocalFileToolDefinition, gitManager_1.gitManagerToolDefinition, xManager_1.xManagerToolDefinition, notionWorkspace_1.notionWorkspaceToolDefinition, audioTranscribe_1.audioTranscribeToolDefinition, summarizeText_1.summarizeTextToolDefinition, scheduleTask_1.scheduleTaskDefinition, cancelTask_1.cancelTaskDefinition];
142
+ const GOOGLE_TOOLS = [googleWorkspace_1.readGmailInboxToolDefinition, googleWorkspace_1.listCalendarEventsToolDefinition, googleWorkspace_1.appendRowToSheetsToolDefinition, googleWorkspace_1.readGoogleDocsToolDefinition, googleWorkspace_1.readGoogleFormResponsesToolDefinition];
143
+ activeTools = [...SYSTEM_TOOLS, ...GOOGLE_TOOLS].filter(t => (0, skillManager_1.isSkillActive)(t.function.name));
144
+ const { sanitizeHistoryForLLM } = require('../utils/historySanitizer');
145
+ const sanitizedHistory = sanitizeHistoryForLLM(history, activeTools);
146
+ let messages = [
147
+ { role: 'system', content: getSystemPrompt('os') },
148
+ ...sanitizedHistory
149
+ ];
150
+ try {
151
+ const context = 'os';
152
+ const SYSTEM_TOOLS = [updateProfile_1.updateProfileToolDefinition, updateIdentity_1.updateIdentityToolDefinition, updateSecurityPolicy_1.updateSecurityPolicyToolDefinition, analyzeDocument_1.analyzeDocumentToolDefinition, readFile_1.readLocalFileToolDefinition, writeFile_1.writeLocalFileToolDefinition, generateExcel_1.generateExcelToolDefinition, executeShell_1.runTerminalCommandToolDefinition, browseWeb_1.browseWebsiteToolDefinition, searchWeb_1.searchWebToolDefinition, editFile_1.editLocalFileToolDefinition, gitManager_1.gitManagerToolDefinition, xManager_1.xManagerToolDefinition, notionWorkspace_1.notionWorkspaceToolDefinition, audioTranscribe_1.audioTranscribeToolDefinition, summarizeText_1.summarizeTextToolDefinition, scheduleTask_1.scheduleTaskDefinition, cancelTask_1.cancelTaskDefinition];
153
+ const GOOGLE_TOOLS = [googleWorkspace_1.readGmailInboxToolDefinition, googleWorkspace_1.listCalendarEventsToolDefinition, googleWorkspace_1.appendRowToSheetsToolDefinition, googleWorkspace_1.readGoogleDocsToolDefinition, googleWorkspace_1.readGoogleFormResponsesToolDefinition];
154
+ let activeTools = [...SYSTEM_TOOLS, ...GOOGLE_TOOLS];
155
+ activeTools = activeTools.filter(t => (0, skillManager_1.isSkillActive)(t.function.name));
156
+ const response = await executeWithRetry(async (client) => {
157
+ return await client.chat.completions.create({
158
+ model: config.llm.model,
159
+ temperature: config.llm.temperature,
160
+ messages: messages,
161
+ tools: activeTools,
162
+ tool_choice: "auto",
163
+ });
164
+ });
165
+ const responseMessage = response.choices[0].message;
166
+ tracker_1.Tracker.addMessage();
167
+ if (response.usage?.total_tokens) {
168
+ tracker_1.Tracker.addTokens(response.usage.total_tokens, config.llm.provider);
169
+ }
170
+ tracker_1.Tracker.addEvent('llm.response', { provider: config.llm.provider, tool_calls: responseMessage.tool_calls?.length || 0 });
171
+ exports.logger.addEntry({
172
+ role: 'assistant',
173
+ content: responseMessage.content || "",
174
+ tool_calls: responseMessage.tool_calls,
175
+ }, sessionId);
176
+ if (responseMessage.tool_calls && responseMessage.tool_calls.length > 0) {
177
+ let canFastReturnAll = true;
178
+ let accumulatedResults = [];
179
+ // Enabled fastReturnTools to eliminate 2nd LLM latency for transaction popups
180
+ const fastReturnTools = [
181
+ 'transfer_token', 'transfer_native', 'swap_token', 'bridge_token',
182
+ 'mint_nft', 'custom_tx', 'revoke_approval', 'supply_aave',
183
+ 'deposit_yield_vault', 'provide_liquidity_v3'
184
+ ];
185
+ for (const _toolCall of responseMessage.tool_calls) {
186
+ const toolCall = _toolCall;
187
+ let result = "";
188
+ let args = {};
189
+ const toolName = toolCall.function.name;
190
+ console.log(picocolors_1.default.yellow(`[⚡ Tool Execution] AI is calling ${toolName}...`));
191
+ if (onProgress)
192
+ onProgress(`_⚡ Running tool: ${toolName}..._`);
193
+ try {
194
+ args = JSON.parse(toolCall.function.arguments);
195
+ }
196
+ catch (parseError) {
197
+ console.error(picocolors_1.default.red(`[LLM Validation Error] Invalid JSON arguments for ${toolName}: ${parseError.message}`));
198
+ result = `[System Error] Arguments for ${toolName} must be valid JSON. Please correct the format. Error: ${parseError.message}`;
199
+ exports.logger.addEntry({
200
+ role: "tool",
201
+ tool_call_id: toolCall.id,
202
+ content: result
203
+ }, sessionId);
204
+ continue;
205
+ }
206
+ if (!(0, skillManager_1.isSkillActive)(toolName)) {
207
+ console.warn(picocolors_1.default.red(`[Security] Blocked illegal execution of disabled skill: ${toolName}`));
208
+ result = `[System Error] Access denied: Skill '${toolName}' is currently disabled by the user.`;
209
+ exports.logger.addEntry({
210
+ role: "tool",
211
+ tool_call_id: toolCall.id,
212
+ content: result
213
+ }, sessionId);
214
+ continue;
215
+ }
216
+ try {
217
+ switch (toolName) {
218
+ case 'update_profile': {
219
+ result = (0, updateProfile_1.updateProfile)(args.content, args.mode);
220
+ break;
221
+ }
222
+ case 'update_identity': {
223
+ result = (0, updateIdentity_1.updateIdentity)(args.content, args.mode);
224
+ break;
225
+ }
226
+ case 'update_security_policy': {
227
+ result = await (0, updateSecurityPolicy_1.updateSecurityPolicy)(args.policy, args.action || 'add');
228
+ break;
229
+ }
230
+ case 'analyze_document': {
231
+ result = await (0, analyzeDocument_1.analyzeDocument)(args.filePath);
232
+ break;
233
+ }
234
+ case 'read_local_file': {
235
+ result = (0, readFile_1.readLocalFile)(args.filePath, args.startLine, args.endLine);
236
+ break;
237
+ }
238
+ case 'edit_local_file': {
239
+ result = (0, editFile_1.editLocalFile)(args.filePath, args.searchString, args.replacementString);
240
+ break;
241
+ }
242
+ case 'execute_git_command': {
243
+ result = await (0, gitManager_1.executeGitCommand)(args.action, args.commitMessage);
244
+ break;
245
+ }
246
+ case 'manage_twitter': {
247
+ result = await (0, xManager_1.manageTwitter)(args.action, args.content, args.username);
248
+ break;
249
+ }
250
+ case 'manage_notion': {
251
+ result = await (0, notionWorkspace_1.manageNotion)(args.action, args.pageId, args.text);
252
+ break;
253
+ }
254
+ case 'transcribe_audio': {
255
+ result = await (0, audioTranscribe_1.transcribeAudio)(args.filePath);
256
+ break;
257
+ }
258
+ case 'summarize_text': {
259
+ result = await (0, summarizeText_1.summarizeText)(args.text, args.focus);
260
+ break;
261
+ }
262
+ case 'write_local_file': {
263
+ result = (0, writeFile_1.writeLocalFile)(args.filePath, args.content);
264
+ break;
265
+ }
266
+ case 'generate_excel_file': {
267
+ result = await (0, generateExcel_1.generateExcelFile)(args.data, args.filePath);
268
+ break;
269
+ }
270
+ case 'run_terminal_command': {
271
+ result = await (0, executeShell_1.runTerminalCommand)(args.command);
272
+ break;
273
+ }
274
+ case 'browse_website': {
275
+ result = await (0, browseWeb_1.browseWebsite)(args.url);
276
+ break;
277
+ }
278
+ case 'search_web': {
279
+ result = await (0, searchWeb_1.searchWeb)(args.query, args.depth);
280
+ break;
281
+ }
282
+ case 'schedule_task': {
283
+ result = await (0, scheduleTask_1.executeScheduleTask)(args);
284
+ break;
285
+ }
286
+ case 'cancel_task': {
287
+ result = await (0, cancelTask_1.executeCancelTask)(args);
288
+ break;
289
+ }
290
+ case 'read_gmail_inbox': {
291
+ result = await (0, googleWorkspace_1.readGmailInbox)(args.maxResults);
292
+ break;
293
+ }
294
+ case 'list_calendar_events': {
295
+ result = await (0, googleWorkspace_1.listCalendarEvents)(args.maxResults);
296
+ break;
297
+ }
298
+ case 'append_row_to_sheets': {
299
+ result = await (0, googleWorkspace_1.appendRowToSheets)(args.spreadsheetId, args.range, args.values);
300
+ break;
301
+ }
302
+ case 'read_google_docs': {
303
+ result = await (0, googleWorkspace_1.readGoogleDocs)(args.documentId);
304
+ break;
305
+ }
306
+ case 'read_google_form_responses': {
307
+ result = await (0, googleWorkspace_1.readGoogleFormResponses)(args.formId);
308
+ break;
309
+ }
310
+ default: {
311
+ result = `Error: Tool ${toolName} is not implemented.`;
312
+ break;
313
+ }
314
+ }
315
+ if (result.includes('[Security Blocked]') || result.startsWith('Error:')) {
316
+ console.log(picocolors_1.default.red(`[❌ Failed] Tool ${toolName} returned an error or was blocked.`));
317
+ }
318
+ else {
319
+ console.log(picocolors_1.default.green(`[✅ Success] Tool ${toolName} executed successfully.`));
320
+ }
321
+ }
322
+ catch (toolError) {
323
+ result = `Error executing ${toolName}: ${toolError.message}`;
324
+ console.error(picocolors_1.default.red(`[❌ Error Crash] Execution of ${toolName} failed completely: ${toolError.message}`));
325
+ }
326
+ exports.logger.addEntry({
327
+ role: 'tool',
328
+ tool_call_id: toolCall.id,
329
+ name: toolName,
330
+ content: result,
331
+ }, sessionId);
332
+ accumulatedResults.push(result);
333
+ if (!fastReturnTools.includes(toolName)) {
334
+ canFastReturnAll = false;
335
+ }
336
+ }
337
+ // V2 Optimization (Expanded in v1.7.4): Zero-LLM Fast Return for data-heavy and read-only tools
338
+ // If all tools already return perfectly formatted markdown, skip the second LLM call to save 5-10s latency!
339
+ if (canFastReturnAll && accumulatedResults.length > 0) {
340
+ const finalContent = accumulatedResults.join('\n\n---\n\n');
341
+ exports.logger.addEntry({ role: 'assistant', content: finalContent }, sessionId);
342
+ return finalContent;
343
+ }
344
+ // Second call to get the final answer after tool execution
345
+ const secondSanitized = sanitizeHistoryForLLM(exports.logger.getHistory(sessionId), activeTools);
346
+ const secondMessages = [
347
+ { role: 'system', content: getSystemPrompt('os') },
348
+ ...secondSanitized
349
+ ];
350
+ const secondResponse = await executeWithRetry(async (client) => {
351
+ return await client.chat.completions.create({
352
+ model: config.llm.model,
353
+ messages: secondMessages,
354
+ });
355
+ });
356
+ if (secondResponse.usage?.total_tokens) {
357
+ tracker_1.Tracker.addTokens(secondResponse.usage.total_tokens, config.llm.provider);
358
+ }
359
+ tracker_1.Tracker.addEvent('llm.final_response', { provider: config.llm.provider });
360
+ let finalContent = secondResponse.choices[0].message.content || "";
361
+ // Clean up orphaned <think> blocks that forgot to output </think>
362
+ finalContent = finalContent.replace(/<thought>[\s\S]*?<\/thought>\n?/gi, '');
363
+ finalContent = finalContent.replace(/<think>[\s\S]*?<\/think>\n?/gi, '');
364
+ if (finalContent.includes('<think>')) {
365
+ finalContent = finalContent.replace(/<think>[\s\S]*?\n\n/i, '');
366
+ finalContent = finalContent.replace(/<think>[\s\S]*$/i, '');
367
+ }
368
+ finalContent = finalContent.trim();
369
+ exports.logger.addEntry({ role: 'assistant', content: finalContent }, sessionId);
370
+ return finalContent;
371
+ }
372
+ let finalContent = responseMessage.content || "No response generated.";
373
+ // Clean up orphaned <think> blocks that forgot to output </think>
374
+ finalContent = finalContent.replace(/<thought>[\s\S]*?<\/thought>\n?/gi, '');
375
+ finalContent = finalContent.replace(/<think>[\s\S]*?<\/think>\n?/gi, '');
376
+ if (finalContent.includes('<think>')) {
377
+ finalContent = finalContent.replace(/<think>[\s\S]*?\n\n/i, '');
378
+ finalContent = finalContent.replace(/<think>[\s\S]*$/i, '');
379
+ }
380
+ finalContent = finalContent.trim();
381
+ return finalContent;
382
+ }
383
+ catch (error) {
384
+ console.error("LLM Error:", error);
385
+ const errorMsg = '⚠️ All models are temporarily rate-limited. Please try again in a few minutes.';
386
+ exports.logger.addEntry({ role: 'assistant', content: errorMsg }, sessionId);
387
+ return errorMsg;
388
+ }
389
+ }