natureco-cli 5.20.4 → 5.21.0
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.
- package/CHANGELOG.md +779 -750
- package/README.md +608 -610
- package/bin/natureco.js +1099 -1095
- package/package.json +95 -94
- package/scripts/generate-qr.js +21 -0
- package/scripts/import-curated-skills-log.json +5 -0
- package/scripts/import-curated-skills.js +262 -0
- package/scripts/import-skills-log.json +167 -0
- package/scripts/import-skills.js +261 -0
- package/scripts/postinstall.js +125 -0
- package/src/commands/agent.js +280 -280
- package/src/commands/ask.js +4 -2
- package/src/commands/chat.js +0 -1
- package/src/commands/help.js +0 -2
- package/src/commands/naturehub.js +206 -373
- package/src/commands/repl.js +52 -62
- package/src/providers/mem0-memory.js +121 -121
- package/src/providers/supermemory-memory.js +117 -117
- package/src/tools/llm_task.js +150 -163
- package/src/tools/mac_alarm.js +199 -199
- package/src/tools/workflow.js +424 -439
- package/src/utils/api.js +1211 -1188
- package/src/utils/cost-tracker.js +361 -360
- package/src/utils/inquirer-wrapper.js +43 -31
- package/src/utils/paste-safe-input.js +346 -334
- package/src/utils/process-errors.js +129 -115
- package/src/utils/provider-detect.js +76 -72
- package/src/utils/skills.js +1 -1
- package/src/utils/system-prompt.js +136 -136
- package/src/utils/tools.js +324 -324
- package/README.md.bak +0 -565
- package/src/tools/http.js.bak +0 -78
package/src/utils/tools.js
CHANGED
|
@@ -1,324 +1,324 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* NatureCo CLI — Tool Definitions for OpenAI-compatible APIs
|
|
3
|
-
*
|
|
4
|
-
* src/tools/*.js dosyalarını OpenAI uyumlu function calling format'ına dönüştürür.
|
|
5
|
-
* v5.7.17: Emoji + toolset + check_fn + registry entegrasyonu.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const fs = require('fs');
|
|
9
|
-
const path = require('path');
|
|
10
|
-
const { globalRegistry } = require('./registry');
|
|
11
|
-
const sandbox = require('./sandbox');
|
|
12
|
-
|
|
13
|
-
// Lazy config read — avoids circular deps
|
|
14
|
-
function _getSandboxLevel() {
|
|
15
|
-
try { return sandbox.getLevel(require('./config').getConfig()); } catch { return 'none'; }
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const TOOLS_DIR = path.join(__dirname, '..', 'tools');
|
|
19
|
-
|
|
20
|
-
// ── Emoji map (central, tek kaynak) ──────────────────────────────────────
|
|
21
|
-
const EMOJI_MAP = {
|
|
22
|
-
// File operations
|
|
23
|
-
read_file: '📖', write_file: '✏️', edit_file: '🖊️', list_dir: '📂', file_search: '🔍', grep_search: '🔎', filesystem: '🗄️',
|
|
24
|
-
// Terminal
|
|
25
|
-
bash: '💻', shell_command: '⌨️',
|
|
26
|
-
// Web
|
|
27
|
-
duckduckgo: '🦆', duckduckgo_search: '🦆', web_search: '🌐', web_readability: '📄', firecrawl: '🔥', searxng: '🔬', searxng_search: '🔬', http_request: '🌍', http: '🌍', exa_search: '🔬', parallel_search: '⚡',
|
|
28
|
-
// Browser
|
|
29
|
-
browser: '🖥️', browser_use: '🌐',
|
|
30
|
-
// Memory
|
|
31
|
-
memory: '🧠', memory_write: '🧠', memory_search: '🔍',
|
|
32
|
-
// Skills
|
|
33
|
-
skill_view: '📚', skills_list: '📋', skill_generate: '✨', skills_autoload: '🔄', skills_marketplace: '🏪', skill_manage: '🛠️', skills_download: '📥',
|
|
34
|
-
// Agent
|
|
35
|
-
delegate_task: '👥', llm_task: '🤖', sub_agent: '👤',
|
|
36
|
-
// Documents
|
|
37
|
-
document_extract: '📄', notebook_edit: '📓', notes_add: '📝',
|
|
38
|
-
// Git
|
|
39
|
-
git: '🔀',
|
|
40
|
-
// Plan / Todo
|
|
41
|
-
plan: '📋', todo_write: '✅',
|
|
42
|
-
// Media
|
|
43
|
-
image_generation: '🎨', video_generation: '🎬', music_generation: '🎵', media_understanding: '📺', text_to_speech: '🔊', speech_to_text: '🎤', voice_chat: '🗣️',
|
|
44
|
-
// macOS
|
|
45
|
-
mac_alarm: '⏰', mac_app_open: '🚀', mac_app_quit: '⏹️', mac_notify: '🔔', macos_screenshot: '📸', phone_control: '📱', phone_control_enhanced: '📱',
|
|
46
|
-
// Calendar
|
|
47
|
-
calendar_add: '📅',
|
|
48
|
-
// Reminder
|
|
49
|
-
reminder_add: '⏰',
|
|
50
|
-
// Dashboard
|
|
51
|
-
dashboard: '📊',
|
|
52
|
-
kanban: '📋',
|
|
53
|
-
// Canvas
|
|
54
|
-
canvas: '🎨',
|
|
55
|
-
// Plugin
|
|
56
|
-
plugin: '🔌',
|
|
57
|
-
// Soul
|
|
58
|
-
soul: '💫',
|
|
59
|
-
// Cron
|
|
60
|
-
cron_create: '⏱️',
|
|
61
|
-
// Thread
|
|
62
|
-
thread_ownership: '🔗',
|
|
63
|
-
// Audio understanding
|
|
64
|
-
audio_understanding: '🎵',
|
|
65
|
-
// Code execution
|
|
66
|
-
code_execution: '⚡',
|
|
67
|
-
// Cross-session
|
|
68
|
-
cross_session_memory: '🔗',
|
|
69
|
-
// v5.10.0: New tools
|
|
70
|
-
url_safety: '🛡️', approval: '✅', checkpoint: '💾', file_state: '🔍',
|
|
71
|
-
pii_redact: '🔒', clarify: '❓', session_search: '🔎', x_search: '🐦',
|
|
72
|
-
discord: '💬', send_message: '📨', async_delegation: '⏳', blueprint: '📐',
|
|
73
|
-
spotify: '🎧', homeassistant: '🏠', microsoft_graph: '📊', computer_use: '🖱️', computer_use_loop: '🔄',
|
|
74
|
-
google_meet: '📹',
|
|
75
|
-
// Orchestrator
|
|
76
|
-
workflow: '⚙️',
|
|
77
|
-
social_open: '🔗', youtube_ac: '🎬', memory_provider: '🗄️',
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
// ── Toolset grouping ─────────────────────────────────────────────────────
|
|
81
|
-
const TOOLSET_MAP = {
|
|
82
|
-
// File
|
|
83
|
-
read_file: 'file', write_file: 'file', edit_file: 'file', list_dir: 'file',
|
|
84
|
-
file_search: 'file', grep_search: 'file', filesystem: 'file',
|
|
85
|
-
// Terminal
|
|
86
|
-
bash: 'terminal', shell_command: 'terminal',
|
|
87
|
-
// Web
|
|
88
|
-
duckduckgo: 'web', web_search: 'web', web_readability: 'web', firecrawl: 'web',
|
|
89
|
-
searxng: 'web', http_request: 'web', http: 'web', exa_search: 'web',
|
|
90
|
-
parallel_search: 'web',
|
|
91
|
-
duckduckgo_search: 'web', searxng_search: 'web',
|
|
92
|
-
// Browser
|
|
93
|
-
browser: 'browser', browser_use: 'browser',
|
|
94
|
-
// Memory
|
|
95
|
-
memory: 'memory', memory_write: 'memory', memory_search: 'memory',
|
|
96
|
-
// Skills
|
|
97
|
-
skill_view: 'skills', skills_list: 'skills', skill_generate: 'skills',
|
|
98
|
-
skills_autoload: 'skills', skills_marketplace: 'skills', skill_manage: 'skills', skills_download: 'skills',
|
|
99
|
-
// Agent
|
|
100
|
-
delegate_task: 'agent', llm_task: 'agent',
|
|
101
|
-
// Documents
|
|
102
|
-
document_extract: 'documents', notebook_edit: 'documents', notes_add: 'documents',
|
|
103
|
-
// Git
|
|
104
|
-
git: 'git',
|
|
105
|
-
// Plan / Todo
|
|
106
|
-
plan: 'planning', todo_write: 'planning',
|
|
107
|
-
// Media
|
|
108
|
-
image_generation: 'media', video_generation: 'media', music_generation: 'media',
|
|
109
|
-
media_understanding: 'media', text_to_speech: 'media', speech_to_text: 'media',
|
|
110
|
-
voice_chat: 'media', audio_understanding: 'media',
|
|
111
|
-
// macOS
|
|
112
|
-
mac_alarm: 'macos', mac_app_open: 'macos', mac_app_quit: 'macos', mac_notify: 'macos',
|
|
113
|
-
macos_screenshot: 'macos', phone_control: 'macos', phone_control_enhanced: 'macos',
|
|
114
|
-
// Calendar
|
|
115
|
-
calendar_add: 'calendar',
|
|
116
|
-
// Reminder
|
|
117
|
-
reminder_add: 'reminders',
|
|
118
|
-
// Other
|
|
119
|
-
dashboard: 'dashboard', canvas: 'canvas', plugin: 'plugins', soul: 'soul',
|
|
120
|
-
kanban: 'planning',
|
|
121
|
-
cron_create: 'cron', thread_ownership: 'threads', code_execution: 'sandbox',
|
|
122
|
-
cross_session_memory: 'memory',
|
|
123
|
-
// v5.10.0: New tools
|
|
124
|
-
url_safety: 'security', approval: 'security', pii_redact: 'security',
|
|
125
|
-
checkpoint: 'system', file_state: 'system',
|
|
126
|
-
clarify: 'agent',
|
|
127
|
-
session_search: 'memory',
|
|
128
|
-
x_search: 'web', discord: 'communication', send_message: 'communication',
|
|
129
|
-
async_delegation: 'agent', blueprint: 'planning', workflow: 'orchestrator',
|
|
130
|
-
spotify: 'media', homeassistant: 'iot', microsoft_graph: 'office',
|
|
131
|
-
computer_use: 'automation', computer_use_loop: 'automation', google_meet: 'communication',
|
|
132
|
-
social_open: 'communication', youtube_ac: 'media',
|
|
133
|
-
sub_agent: 'agent', memory_provider: 'memory',
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
// ── check_fn'ler (tool availability kontrolleri) ────────────────────────
|
|
137
|
-
function _checkBrowser() {
|
|
138
|
-
try {
|
|
139
|
-
require.resolve('playwright');
|
|
140
|
-
return true;
|
|
141
|
-
} catch { return false; }
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function _checkDuckDuckGo() {
|
|
145
|
-
return true; // API-based, always available
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function _checkMacOSTools() {
|
|
149
|
-
return process.platform === 'darwin';
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const CHECK_FN_MAP = {
|
|
153
|
-
browser: _checkBrowser,
|
|
154
|
-
mac_alarm: _checkMacOSTools,
|
|
155
|
-
mac_app_open: _checkMacOSTools,
|
|
156
|
-
mac_app_quit: _checkMacOSTools,
|
|
157
|
-
mac_notify: _checkMacOSTools,
|
|
158
|
-
macos_screenshot: _checkMacOSTools,
|
|
159
|
-
phone_control: _checkMacOSTools,
|
|
160
|
-
phone_control_enhanced: _checkMacOSTools,
|
|
161
|
-
// v5.10.0: google_meet create macOS-only; computer_use partial cross-platform
|
|
162
|
-
google_meet: () => process.platform === 'darwin' || true, // only 'create' is macOS-only, 'open' cross-platform
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
// ── Provider filtering ───────────────────────────────────────────────────
|
|
166
|
-
function getToolsForProvider(allTools, providerUrl) {
|
|
167
|
-
const url = (providerUrl || '').toLowerCase();
|
|
168
|
-
if (url.includes('groq.com')) {
|
|
169
|
-
const allowed = ['read_file', 'write_file', 'bash', 'shell_command', 'list_dir', 'soul', 'memory', 'memory_write', 'memory_search', 'filesystem', 'grep_search'];
|
|
170
|
-
return allTools.filter(t => allowed.includes(t.name));
|
|
171
|
-
}
|
|
172
|
-
return allTools;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function loadToolDefinitions() {
|
|
176
|
-
const tools = [];
|
|
177
|
-
const files = fs.readdirSync(TOOLS_DIR).filter(f => f.endsWith('.js'));
|
|
178
|
-
|
|
179
|
-
let isGroq = false;
|
|
180
|
-
try {
|
|
181
|
-
const { getConfig } = require('./config');
|
|
182
|
-
const cfg = getConfig();
|
|
183
|
-
if (cfg.providerUrl && cfg.providerUrl.toLowerCase().includes('groq.com')) {
|
|
184
|
-
isGroq = true;
|
|
185
|
-
}
|
|
186
|
-
} catch (e) {}
|
|
187
|
-
|
|
188
|
-
let disabledTools = new Set();
|
|
189
|
-
try {
|
|
190
|
-
const { getConfig } = require('./config');
|
|
191
|
-
const cfg = getConfig();
|
|
192
|
-
if (Array.isArray(cfg.disabledTools)) disabledTools = new Set(cfg.disabledTools);
|
|
193
|
-
} catch (e) {}
|
|
194
|
-
|
|
195
|
-
const GROQ_ALLOWED = new Set([
|
|
196
|
-
'read_file', 'write_file', 'list_dir', 'bash', 'shell_command',
|
|
197
|
-
'soul', 'memory', 'memory_write', 'memory_search', 'filesystem', 'grep_search'
|
|
198
|
-
]);
|
|
199
|
-
|
|
200
|
-
for (const file of files) {
|
|
201
|
-
try {
|
|
202
|
-
const toolPath = path.join(TOOLS_DIR, file);
|
|
203
|
-
const mod = require(toolPath);
|
|
204
|
-
const toolName = mod.name || path.basename(file, '.js');
|
|
205
|
-
|
|
206
|
-
if (isGroq && !GROQ_ALLOWED.has(toolName)) continue;
|
|
207
|
-
if (disabledTools.has(toolName)) continue;
|
|
208
|
-
|
|
209
|
-
const meta = {
|
|
210
|
-
name: toolName,
|
|
211
|
-
description: mod.description || `${path.basename(file, '.js')} tool`,
|
|
212
|
-
parameters: mod.parameters || mod.inputSchema || { type: 'object', properties: {} },
|
|
213
|
-
execute: mod.execute || (mod.default && mod.default.execute) || null,
|
|
214
|
-
emoji: EMOJI_MAP[toolName] || '',
|
|
215
|
-
toolset: TOOLSET_MAP[toolName] || 'general',
|
|
216
|
-
checkFn: CHECK_FN_MAP[toolName] || null,
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
if (meta.execute) {
|
|
220
|
-
tools.push(meta);
|
|
221
|
-
// Registry'ye kaydet
|
|
222
|
-
globalRegistry.register({
|
|
223
|
-
name: meta.name,
|
|
224
|
-
toolset: meta.toolset,
|
|
225
|
-
schema: { name: meta.name, description: meta.description, parameters: meta.parameters },
|
|
226
|
-
handler: meta.execute,
|
|
227
|
-
checkFn: meta.checkFn,
|
|
228
|
-
emoji: meta.emoji,
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
} catch (e) {
|
|
232
|
-
// Sessizce atla
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
return tools;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const ALIAS_MAP = {
|
|
239
|
-
'brave_search': 'duckduckgo_search', 'brave-web-search': 'duckduckgo_search',
|
|
240
|
-
'google_search': 'duckduckgo_search', 'web_search': 'duckduckgo_search',
|
|
241
|
-
'browse': 'browser', 'shell': 'bash', 'bash_command': 'bash',
|
|
242
|
-
'execute_command': 'bash', 'run_command': 'bash',
|
|
243
|
-
'http': 'http_request',
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
const BLOCKED_NAMES = new Set([
|
|
247
|
-
'brave_search', 'brave-web-search', 'google_search', 'web_search',
|
|
248
|
-
'browse', 'open', 'search', 'shell', 'bash_command', 'execute_command',
|
|
249
|
-
'run_command', 'sql', 'query', 'lookup', 'http',
|
|
250
|
-
]);
|
|
251
|
-
|
|
252
|
-
// ── check_fn TTL cache (Hermes-style, ~30s) ────────────────────────────
|
|
253
|
-
const _checkFnCache = new Map();
|
|
254
|
-
function _cachedCheckFn(fn, key) {
|
|
255
|
-
const now = Date.now();
|
|
256
|
-
const cached = _checkFnCache.get(key);
|
|
257
|
-
if (cached && now - cached.ts < 30000) return cached.result;
|
|
258
|
-
let result
|
|
259
|
-
try { result = fn() !== false; } catch { result = false; }
|
|
260
|
-
_checkFnCache.set(key, { result, ts: now });
|
|
261
|
-
return result;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
function toOpenAIFormat(toolDefs) {
|
|
265
|
-
return toolDefs
|
|
266
|
-
.filter(t => !BLOCKED_NAMES.has(t.name))
|
|
267
|
-
.filter(t => {
|
|
268
|
-
if (t.checkFn) {
|
|
269
|
-
return _cachedCheckFn(t.checkFn, t.name);
|
|
270
|
-
}
|
|
271
|
-
return true;
|
|
272
|
-
})
|
|
273
|
-
.map(t => {
|
|
274
|
-
let name = t.name;
|
|
275
|
-
if (ALIAS_MAP[name]) name = ALIAS_MAP[name];
|
|
276
|
-
|
|
277
|
-
const cleanParams = JSON.parse(JSON.stringify(t.parameters || {}));
|
|
278
|
-
if (cleanParams.properties) {
|
|
279
|
-
Object.keys(cleanParams.properties).forEach(key => {
|
|
280
|
-
const prop = cleanParams.properties[key];
|
|
281
|
-
if (Array.isArray(prop.type)) prop.type = prop.type[0];
|
|
282
|
-
delete prop.additionalProperties;
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
return {
|
|
287
|
-
type: 'function',
|
|
288
|
-
function: { name, description: t.description, parameters: cleanParams },
|
|
289
|
-
};
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
async function executeTool(toolName, args, toolDefs) {
|
|
294
|
-
const tool = toolDefs.find(t => t.name === toolName);
|
|
295
|
-
if (!tool) return { error: `Tool bulunamadı: ${toolName}` };
|
|
296
|
-
if (!tool.execute) return { error: `Tool execute fonksiyonu yok: ${toolName}` };
|
|
297
|
-
// checkFn — tool disabled? (re-check at runtime with cache)
|
|
298
|
-
if (tool.checkFn) {
|
|
299
|
-
if (!_cachedCheckFn(tool.checkFn, tool.name)) {
|
|
300
|
-
return { error: `${toolName} şu anda kullanılamıyor (check_fn engelledi)` };
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// Sandbox restrictions for bash/shell_command
|
|
305
|
-
if (toolName === 'bash' || toolName === 'shell_command') {
|
|
306
|
-
const level = _getSandboxLevel();
|
|
307
|
-
const cmd = (args && args.command) || '';
|
|
308
|
-
if (level === 'strict' && sandbox.isNetworkCommand(cmd)) {
|
|
309
|
-
return { error: 'strict sandbox: network komutları engellendi. Daha düşük sandbox seviyesi kullanın.' };
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
try {
|
|
314
|
-
const result = await tool.execute(args || {});
|
|
315
|
-
return { result };
|
|
316
|
-
} catch (e) {
|
|
317
|
-
return { error: e.message || String(e) };
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
module.exports = {
|
|
322
|
-
loadToolDefinitions, toOpenAIFormat, executeTool, getToolsForProvider,
|
|
323
|
-
EMOJI_MAP, TOOLSET_MAP, CHECK_FN_MAP,
|
|
324
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* NatureCo CLI — Tool Definitions for OpenAI-compatible APIs
|
|
3
|
+
*
|
|
4
|
+
* src/tools/*.js dosyalarını OpenAI uyumlu function calling format'ına dönüştürür.
|
|
5
|
+
* v5.7.17: Emoji + toolset + check_fn + registry entegrasyonu.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { globalRegistry } = require('./registry');
|
|
11
|
+
const sandbox = require('./sandbox');
|
|
12
|
+
|
|
13
|
+
// Lazy config read — avoids circular deps
|
|
14
|
+
function _getSandboxLevel() {
|
|
15
|
+
try { return sandbox.getLevel(require('./config').getConfig()); } catch { return 'none'; }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const TOOLS_DIR = path.join(__dirname, '..', 'tools');
|
|
19
|
+
|
|
20
|
+
// ── Emoji map (central, tek kaynak) ──────────────────────────────────────
|
|
21
|
+
const EMOJI_MAP = {
|
|
22
|
+
// File operations
|
|
23
|
+
read_file: '📖', write_file: '✏️', edit_file: '🖊️', list_dir: '📂', file_search: '🔍', grep_search: '🔎', filesystem: '🗄️',
|
|
24
|
+
// Terminal
|
|
25
|
+
bash: '💻', shell_command: '⌨️',
|
|
26
|
+
// Web
|
|
27
|
+
duckduckgo: '🦆', duckduckgo_search: '🦆', web_search: '🌐', web_readability: '📄', firecrawl: '🔥', searxng: '🔬', searxng_search: '🔬', http_request: '🌍', http: '🌍', exa_search: '🔬', parallel_search: '⚡',
|
|
28
|
+
// Browser
|
|
29
|
+
browser: '🖥️', browser_use: '🌐',
|
|
30
|
+
// Memory
|
|
31
|
+
memory: '🧠', memory_write: '🧠', memory_search: '🔍',
|
|
32
|
+
// Skills
|
|
33
|
+
skill_view: '📚', skills_list: '📋', skill_generate: '✨', skills_autoload: '🔄', skills_marketplace: '🏪', skill_manage: '🛠️', skills_download: '📥',
|
|
34
|
+
// Agent
|
|
35
|
+
delegate_task: '👥', llm_task: '🤖', sub_agent: '👤',
|
|
36
|
+
// Documents
|
|
37
|
+
document_extract: '📄', notebook_edit: '📓', notes_add: '📝',
|
|
38
|
+
// Git
|
|
39
|
+
git: '🔀',
|
|
40
|
+
// Plan / Todo
|
|
41
|
+
plan: '📋', todo_write: '✅',
|
|
42
|
+
// Media
|
|
43
|
+
image_generation: '🎨', video_generation: '🎬', music_generation: '🎵', media_understanding: '📺', text_to_speech: '🔊', speech_to_text: '🎤', voice_chat: '🗣️',
|
|
44
|
+
// macOS
|
|
45
|
+
mac_alarm: '⏰', mac_app_open: '🚀', mac_app_quit: '⏹️', mac_notify: '🔔', macos_screenshot: '📸', phone_control: '📱', phone_control_enhanced: '📱',
|
|
46
|
+
// Calendar
|
|
47
|
+
calendar_add: '📅',
|
|
48
|
+
// Reminder
|
|
49
|
+
reminder_add: '⏰',
|
|
50
|
+
// Dashboard
|
|
51
|
+
dashboard: '📊',
|
|
52
|
+
kanban: '📋',
|
|
53
|
+
// Canvas
|
|
54
|
+
canvas: '🎨',
|
|
55
|
+
// Plugin
|
|
56
|
+
plugin: '🔌',
|
|
57
|
+
// Soul
|
|
58
|
+
soul: '💫',
|
|
59
|
+
// Cron
|
|
60
|
+
cron_create: '⏱️',
|
|
61
|
+
// Thread
|
|
62
|
+
thread_ownership: '🔗',
|
|
63
|
+
// Audio understanding
|
|
64
|
+
audio_understanding: '🎵',
|
|
65
|
+
// Code execution
|
|
66
|
+
code_execution: '⚡',
|
|
67
|
+
// Cross-session
|
|
68
|
+
cross_session_memory: '🔗',
|
|
69
|
+
// v5.10.0: New tools
|
|
70
|
+
url_safety: '🛡️', approval: '✅', checkpoint: '💾', file_state: '🔍',
|
|
71
|
+
pii_redact: '🔒', clarify: '❓', session_search: '🔎', x_search: '🐦',
|
|
72
|
+
discord: '💬', send_message: '📨', async_delegation: '⏳', blueprint: '📐',
|
|
73
|
+
spotify: '🎧', homeassistant: '🏠', microsoft_graph: '📊', computer_use: '🖱️', computer_use_loop: '🔄',
|
|
74
|
+
google_meet: '📹',
|
|
75
|
+
// Orchestrator
|
|
76
|
+
workflow: '⚙️',
|
|
77
|
+
social_open: '🔗', youtube_ac: '🎬', memory_provider: '🗄️',
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// ── Toolset grouping ─────────────────────────────────────────────────────
|
|
81
|
+
const TOOLSET_MAP = {
|
|
82
|
+
// File
|
|
83
|
+
read_file: 'file', write_file: 'file', edit_file: 'file', list_dir: 'file',
|
|
84
|
+
file_search: 'file', grep_search: 'file', filesystem: 'file',
|
|
85
|
+
// Terminal
|
|
86
|
+
bash: 'terminal', shell_command: 'terminal',
|
|
87
|
+
// Web
|
|
88
|
+
duckduckgo: 'web', web_search: 'web', web_readability: 'web', firecrawl: 'web',
|
|
89
|
+
searxng: 'web', http_request: 'web', http: 'web', exa_search: 'web',
|
|
90
|
+
parallel_search: 'web',
|
|
91
|
+
duckduckgo_search: 'web', searxng_search: 'web',
|
|
92
|
+
// Browser
|
|
93
|
+
browser: 'browser', browser_use: 'browser',
|
|
94
|
+
// Memory
|
|
95
|
+
memory: 'memory', memory_write: 'memory', memory_search: 'memory',
|
|
96
|
+
// Skills
|
|
97
|
+
skill_view: 'skills', skills_list: 'skills', skill_generate: 'skills',
|
|
98
|
+
skills_autoload: 'skills', skills_marketplace: 'skills', skill_manage: 'skills', skills_download: 'skills',
|
|
99
|
+
// Agent
|
|
100
|
+
delegate_task: 'agent', llm_task: 'agent',
|
|
101
|
+
// Documents
|
|
102
|
+
document_extract: 'documents', notebook_edit: 'documents', notes_add: 'documents',
|
|
103
|
+
// Git
|
|
104
|
+
git: 'git',
|
|
105
|
+
// Plan / Todo
|
|
106
|
+
plan: 'planning', todo_write: 'planning',
|
|
107
|
+
// Media
|
|
108
|
+
image_generation: 'media', video_generation: 'media', music_generation: 'media',
|
|
109
|
+
media_understanding: 'media', text_to_speech: 'media', speech_to_text: 'media',
|
|
110
|
+
voice_chat: 'media', audio_understanding: 'media',
|
|
111
|
+
// macOS
|
|
112
|
+
mac_alarm: 'macos', mac_app_open: 'macos', mac_app_quit: 'macos', mac_notify: 'macos',
|
|
113
|
+
macos_screenshot: 'macos', phone_control: 'macos', phone_control_enhanced: 'macos',
|
|
114
|
+
// Calendar
|
|
115
|
+
calendar_add: 'calendar',
|
|
116
|
+
// Reminder
|
|
117
|
+
reminder_add: 'reminders',
|
|
118
|
+
// Other
|
|
119
|
+
dashboard: 'dashboard', canvas: 'canvas', plugin: 'plugins', soul: 'soul',
|
|
120
|
+
kanban: 'planning',
|
|
121
|
+
cron_create: 'cron', thread_ownership: 'threads', code_execution: 'sandbox',
|
|
122
|
+
cross_session_memory: 'memory',
|
|
123
|
+
// v5.10.0: New tools
|
|
124
|
+
url_safety: 'security', approval: 'security', pii_redact: 'security',
|
|
125
|
+
checkpoint: 'system', file_state: 'system',
|
|
126
|
+
clarify: 'agent',
|
|
127
|
+
session_search: 'memory',
|
|
128
|
+
x_search: 'web', discord: 'communication', send_message: 'communication',
|
|
129
|
+
async_delegation: 'agent', blueprint: 'planning', workflow: 'orchestrator',
|
|
130
|
+
spotify: 'media', homeassistant: 'iot', microsoft_graph: 'office',
|
|
131
|
+
computer_use: 'automation', computer_use_loop: 'automation', google_meet: 'communication',
|
|
132
|
+
social_open: 'communication', youtube_ac: 'media',
|
|
133
|
+
sub_agent: 'agent', memory_provider: 'memory',
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// ── check_fn'ler (tool availability kontrolleri) ────────────────────────
|
|
137
|
+
function _checkBrowser() {
|
|
138
|
+
try {
|
|
139
|
+
require.resolve('playwright');
|
|
140
|
+
return true;
|
|
141
|
+
} catch { return false; }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function _checkDuckDuckGo() {
|
|
145
|
+
return true; // API-based, always available
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function _checkMacOSTools() {
|
|
149
|
+
return process.platform === 'darwin';
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const CHECK_FN_MAP = {
|
|
153
|
+
browser: _checkBrowser,
|
|
154
|
+
mac_alarm: _checkMacOSTools,
|
|
155
|
+
mac_app_open: _checkMacOSTools,
|
|
156
|
+
mac_app_quit: _checkMacOSTools,
|
|
157
|
+
mac_notify: _checkMacOSTools,
|
|
158
|
+
macos_screenshot: _checkMacOSTools,
|
|
159
|
+
phone_control: _checkMacOSTools,
|
|
160
|
+
phone_control_enhanced: _checkMacOSTools,
|
|
161
|
+
// v5.10.0: google_meet create macOS-only; computer_use partial cross-platform
|
|
162
|
+
google_meet: () => process.platform === 'darwin' || true, // only 'create' is macOS-only, 'open' cross-platform
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// ── Provider filtering ───────────────────────────────────────────────────
|
|
166
|
+
function getToolsForProvider(allTools, providerUrl) {
|
|
167
|
+
const url = (providerUrl || '').toLowerCase();
|
|
168
|
+
if (url.includes('groq.com')) {
|
|
169
|
+
const allowed = ['read_file', 'write_file', 'bash', 'shell_command', 'list_dir', 'soul', 'memory', 'memory_write', 'memory_search', 'filesystem', 'grep_search'];
|
|
170
|
+
return allTools.filter(t => allowed.includes(t.name));
|
|
171
|
+
}
|
|
172
|
+
return allTools;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function loadToolDefinitions() {
|
|
176
|
+
const tools = [];
|
|
177
|
+
const files = fs.readdirSync(TOOLS_DIR).filter(f => f.endsWith('.js'));
|
|
178
|
+
|
|
179
|
+
let isGroq = false;
|
|
180
|
+
try {
|
|
181
|
+
const { getConfig } = require('./config');
|
|
182
|
+
const cfg = getConfig();
|
|
183
|
+
if (cfg.providerUrl && cfg.providerUrl.toLowerCase().includes('groq.com')) {
|
|
184
|
+
isGroq = true;
|
|
185
|
+
}
|
|
186
|
+
} catch (e) {}
|
|
187
|
+
|
|
188
|
+
let disabledTools = new Set();
|
|
189
|
+
try {
|
|
190
|
+
const { getConfig } = require('./config');
|
|
191
|
+
const cfg = getConfig();
|
|
192
|
+
if (Array.isArray(cfg.disabledTools)) disabledTools = new Set(cfg.disabledTools);
|
|
193
|
+
} catch (e) {}
|
|
194
|
+
|
|
195
|
+
const GROQ_ALLOWED = new Set([
|
|
196
|
+
'read_file', 'write_file', 'list_dir', 'bash', 'shell_command',
|
|
197
|
+
'soul', 'memory', 'memory_write', 'memory_search', 'filesystem', 'grep_search'
|
|
198
|
+
]);
|
|
199
|
+
|
|
200
|
+
for (const file of files) {
|
|
201
|
+
try {
|
|
202
|
+
const toolPath = path.join(TOOLS_DIR, file);
|
|
203
|
+
const mod = require(toolPath);
|
|
204
|
+
const toolName = mod.name || path.basename(file, '.js');
|
|
205
|
+
|
|
206
|
+
if (isGroq && !GROQ_ALLOWED.has(toolName)) continue;
|
|
207
|
+
if (disabledTools.has(toolName)) continue;
|
|
208
|
+
|
|
209
|
+
const meta = {
|
|
210
|
+
name: toolName,
|
|
211
|
+
description: mod.description || `${path.basename(file, '.js')} tool`,
|
|
212
|
+
parameters: mod.parameters || mod.inputSchema || { type: 'object', properties: {} },
|
|
213
|
+
execute: mod.execute || (mod.default && mod.default.execute) || null,
|
|
214
|
+
emoji: EMOJI_MAP[toolName] || '',
|
|
215
|
+
toolset: TOOLSET_MAP[toolName] || 'general',
|
|
216
|
+
checkFn: CHECK_FN_MAP[toolName] || null,
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
if (meta.execute) {
|
|
220
|
+
tools.push(meta);
|
|
221
|
+
// Registry'ye kaydet
|
|
222
|
+
globalRegistry.register({
|
|
223
|
+
name: meta.name,
|
|
224
|
+
toolset: meta.toolset,
|
|
225
|
+
schema: { name: meta.name, description: meta.description, parameters: meta.parameters },
|
|
226
|
+
handler: meta.execute,
|
|
227
|
+
checkFn: meta.checkFn,
|
|
228
|
+
emoji: meta.emoji,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
} catch (e) {
|
|
232
|
+
// Sessizce atla
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return tools;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const ALIAS_MAP = {
|
|
239
|
+
'brave_search': 'duckduckgo_search', 'brave-web-search': 'duckduckgo_search',
|
|
240
|
+
'google_search': 'duckduckgo_search', 'web_search': 'duckduckgo_search',
|
|
241
|
+
'browse': 'browser', 'shell': 'bash', 'bash_command': 'bash',
|
|
242
|
+
'execute_command': 'bash', 'run_command': 'bash',
|
|
243
|
+
'http': 'http_request',
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const BLOCKED_NAMES = new Set([
|
|
247
|
+
'brave_search', 'brave-web-search', 'google_search', 'web_search',
|
|
248
|
+
'browse', 'open', 'search', 'shell', 'bash_command', 'execute_command',
|
|
249
|
+
'run_command', 'sql', 'query', 'lookup', 'http',
|
|
250
|
+
]);
|
|
251
|
+
|
|
252
|
+
// ── check_fn TTL cache (Hermes-style, ~30s) ────────────────────────────
|
|
253
|
+
const _checkFnCache = new Map();
|
|
254
|
+
function _cachedCheckFn(fn, key) {
|
|
255
|
+
const now = Date.now();
|
|
256
|
+
const cached = _checkFnCache.get(key);
|
|
257
|
+
if (cached && now - cached.ts < 30000) return cached.result;
|
|
258
|
+
let result;
|
|
259
|
+
try { result = fn() !== false; } catch { result = false; }
|
|
260
|
+
_checkFnCache.set(key, { result, ts: now });
|
|
261
|
+
return result;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function toOpenAIFormat(toolDefs) {
|
|
265
|
+
return toolDefs
|
|
266
|
+
.filter(t => !BLOCKED_NAMES.has(t.name))
|
|
267
|
+
.filter(t => {
|
|
268
|
+
if (t.checkFn) {
|
|
269
|
+
return _cachedCheckFn(t.checkFn, t.name);
|
|
270
|
+
}
|
|
271
|
+
return true;
|
|
272
|
+
})
|
|
273
|
+
.map(t => {
|
|
274
|
+
let name = t.name;
|
|
275
|
+
if (ALIAS_MAP[name]) name = ALIAS_MAP[name];
|
|
276
|
+
|
|
277
|
+
const cleanParams = JSON.parse(JSON.stringify(t.parameters || {}));
|
|
278
|
+
if (cleanParams.properties) {
|
|
279
|
+
Object.keys(cleanParams.properties).forEach(key => {
|
|
280
|
+
const prop = cleanParams.properties[key];
|
|
281
|
+
if (Array.isArray(prop.type)) prop.type = prop.type[0];
|
|
282
|
+
delete prop.additionalProperties;
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return {
|
|
287
|
+
type: 'function',
|
|
288
|
+
function: { name, description: t.description, parameters: cleanParams },
|
|
289
|
+
};
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
async function executeTool(toolName, args, toolDefs) {
|
|
294
|
+
const tool = toolDefs.find(t => t.name === toolName);
|
|
295
|
+
if (!tool) return { error: `Tool bulunamadı: ${toolName}` };
|
|
296
|
+
if (!tool.execute) return { error: `Tool execute fonksiyonu yok: ${toolName}` };
|
|
297
|
+
// checkFn — tool disabled? (re-check at runtime with cache)
|
|
298
|
+
if (tool.checkFn) {
|
|
299
|
+
if (!_cachedCheckFn(tool.checkFn, tool.name)) {
|
|
300
|
+
return { error: `${toolName} şu anda kullanılamıyor (check_fn engelledi)` };
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Sandbox restrictions for bash/shell_command
|
|
305
|
+
if (toolName === 'bash' || toolName === 'shell_command') {
|
|
306
|
+
const level = _getSandboxLevel();
|
|
307
|
+
const cmd = (args && args.command) || '';
|
|
308
|
+
if (level === 'strict' && sandbox.isNetworkCommand(cmd)) {
|
|
309
|
+
return { error: 'strict sandbox: network komutları engellendi. Daha düşük sandbox seviyesi kullanın.' };
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
const result = await tool.execute(args || {});
|
|
315
|
+
return { result };
|
|
316
|
+
} catch (e) {
|
|
317
|
+
return { error: e.message || String(e) };
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
module.exports = {
|
|
322
|
+
loadToolDefinitions, toOpenAIFormat, executeTool, getToolsForProvider,
|
|
323
|
+
EMOJI_MAP, TOOLSET_MAP, CHECK_FN_MAP,
|
|
324
|
+
};
|