natureco-cli 5.15.0 → 5.16.1
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/package.json +1 -1
- package/src/tools/computer_use.js +210 -57
- package/src/tools/sub_agent.js +96 -0
- package/src/utils/tools.js +7 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "natureco-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.16.1",
|
|
4
4
|
"description": "OpenClaw'dan daha güvenli, daha hızlı, daha ucuz AI agent CLI. Multi-agent, self-evolving skills, audit log, maliyet optimizasyonu ve NatureCo platform-native.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"natureco": "bin/natureco.js"
|
|
@@ -1,138 +1,291 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { spawnSync } = require('child_process');
|
|
2
2
|
const os = require('os');
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
|
|
6
6
|
const PLATFORM = os.platform();
|
|
7
7
|
|
|
8
|
+
const KEY_MAP_DARWIN = {
|
|
9
|
+
enter: 'return',
|
|
10
|
+
return: 'return',
|
|
11
|
+
tab: 'tab',
|
|
12
|
+
escape: 'escape',
|
|
13
|
+
esc: 'escape',
|
|
14
|
+
up: 'up',
|
|
15
|
+
down: 'down',
|
|
16
|
+
left: 'left',
|
|
17
|
+
right: 'right',
|
|
18
|
+
backspace: 'delete',
|
|
19
|
+
delete: 'forwarddelete',
|
|
20
|
+
forwarddelete: 'forwarddelete',
|
|
21
|
+
home: 'home',
|
|
22
|
+
end: 'end',
|
|
23
|
+
pageup: 'page up',
|
|
24
|
+
pagedown: 'page down',
|
|
25
|
+
space: 'space',
|
|
26
|
+
' ': 'space',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const MODIFIER_MAP = {
|
|
30
|
+
command: 'command down',
|
|
31
|
+
cmd: 'command down',
|
|
32
|
+
option: 'option down',
|
|
33
|
+
alt: 'option down',
|
|
34
|
+
control: 'control down',
|
|
35
|
+
ctrl: 'control down',
|
|
36
|
+
shift: 'shift down',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function escapeText(s) {
|
|
40
|
+
return s.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function osaScript(script, timeoutMs = 10000) {
|
|
44
|
+
const result = spawnSync('osascript', ['-e', script], {
|
|
45
|
+
timeout: timeoutMs,
|
|
46
|
+
encoding: 'utf8',
|
|
47
|
+
maxBuffer: 1024 * 1024,
|
|
48
|
+
});
|
|
49
|
+
if (result.error) {
|
|
50
|
+
if (result.error.code === 'ETIMEDOUT') {
|
|
51
|
+
return { success: false, error: 'osascript timed out after ' + timeoutMs + 'ms' };
|
|
52
|
+
}
|
|
53
|
+
return { success: false, error: result.error.message };
|
|
54
|
+
}
|
|
55
|
+
if (result.status !== 0) {
|
|
56
|
+
const msg = result.stderr || result.stdout || 'unknown error';
|
|
57
|
+
let friendly = msg;
|
|
58
|
+
if (msg.includes('yardımcı erişime izin verilmiyor') || msg.includes('access for assistive devices')) {
|
|
59
|
+
friendly = 'Accessibility izni gerekli. System Settings > Privacy & Security > Accessibility > Terminal/iTerm2\'ye izin verin.';
|
|
60
|
+
} else if (msg.includes('(-1700') || msg.includes('can\'t convert')) {
|
|
61
|
+
friendly = 'AppleScript hatasi: ' + msg.slice(0, 200);
|
|
62
|
+
}
|
|
63
|
+
return { success: false, error: friendly };
|
|
64
|
+
}
|
|
65
|
+
return { success: true, data: result.stdout };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function checkAccessibility() {
|
|
69
|
+
const r = osaScript('tell application "System Events" to get name of first process whose frontmost is true', 3000);
|
|
70
|
+
return r.success;
|
|
71
|
+
}
|
|
72
|
+
|
|
8
73
|
async function computerUse(params) {
|
|
9
|
-
const { action, x, y, key, text, button, clicks,
|
|
74
|
+
const { action, x, y, key, text, button, clicks, file } = params;
|
|
10
75
|
|
|
11
76
|
if (action === 'screenshot') {
|
|
12
77
|
const outputFile = file || path.join(os.tmpdir(), 'natureco_screen_' + Date.now() + '.png');
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
78
|
+
try {
|
|
79
|
+
if (PLATFORM === 'darwin') {
|
|
80
|
+
spawnSync('screencapture', ['-x', outputFile], { timeout: 5000 });
|
|
81
|
+
} else if (PLATFORM === 'win32') {
|
|
82
|
+
spawnSync('powershell', ['-Command',
|
|
83
|
+
'Add-Type -AssemblyName System.Windows.Forms; ' +
|
|
84
|
+
'$bmp = [System.Drawing.Bitmap]::new([System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Width, [System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Height); ' +
|
|
85
|
+
'$g = [System.Drawing.Graphics]::FromImage($bmp); ' +
|
|
86
|
+
'$g.CopyFromScreen(0, 0, 0, 0, $bmp.Size); ' +
|
|
87
|
+
'$bmp.Save("' + outputFile.replace(/"/g, '') + '", [System.Drawing.Imaging.ImageFormat]::Png)'
|
|
88
|
+
], { timeout: 10000 });
|
|
89
|
+
} else {
|
|
90
|
+
spawnSync('import', ['-window', 'root', outputFile], { timeout: 5000 });
|
|
91
|
+
}
|
|
92
|
+
return { success: true, file: outputFile, platform: PLATFORM, note: 'Ekran goruntusu alindi' };
|
|
93
|
+
} catch (e) {
|
|
94
|
+
return { success: false, error: 'Screenshot hatasi: ' + e.message };
|
|
19
95
|
}
|
|
20
|
-
return { success: true, file: outputFile, platform: PLATFORM, note: 'Ekran goruntusu alindi: ' + outputFile };
|
|
21
96
|
}
|
|
22
97
|
|
|
23
98
|
if (action === 'click') {
|
|
24
99
|
if (typeof x !== 'number' || typeof y !== 'number') return { success: false, error: 'x ve y gerekli' };
|
|
25
100
|
const btn = button || 'left';
|
|
26
101
|
if (PLATFORM === 'darwin') {
|
|
27
|
-
|
|
28
|
-
|
|
102
|
+
const acc = checkAccessibility();
|
|
103
|
+
if (!acc) return { success: false, error: 'Accessibility izni gerekli. System Settings > Privacy & Security > Accessibility > Terminal\'e izin verin.' };
|
|
104
|
+
const r = osaScript('tell application "System Events" to click at {' + x + ', ' + y + '}');
|
|
105
|
+
if (!r.success) return r;
|
|
106
|
+
return { success: true, action: 'click', x, y, button: btn };
|
|
107
|
+
}
|
|
108
|
+
if (PLATFORM === 'win32') {
|
|
29
109
|
const c = clicks || 1;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
110
|
+
spawnSync('powershell', ['-Command',
|
|
111
|
+
'[System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(' + x + ', ' + y + '); ' +
|
|
112
|
+
'[System.Windows.Forms.SendKeys]::SendWait("' + (c > 1 ? '{DOUBLECLICK}' : '{CLICK}') + '")'
|
|
113
|
+
], { timeout: 5000 });
|
|
114
|
+
return { success: true, action: 'click', x, y, button: btn };
|
|
33
115
|
}
|
|
34
|
-
|
|
116
|
+
spawnSync('xdotool', ['mousemove', String(x), String(y), 'click', '1'], { timeout: 5000 });
|
|
117
|
+
return { success: true, action: 'click', x, y, button: btn };
|
|
35
118
|
}
|
|
36
119
|
|
|
37
120
|
if (action === 'type') {
|
|
38
121
|
if (!text) return { success: false, error: 'text gerekli' };
|
|
39
122
|
if (PLATFORM === 'darwin') {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
123
|
+
const acc = checkAccessibility();
|
|
124
|
+
if (!acc) return { success: false, error: 'Accessibility izni gerekli' };
|
|
125
|
+
const r = osaScript('tell application "System Events" to keystroke "' + escapeText(text) + '"');
|
|
126
|
+
if (!r.success) return r;
|
|
127
|
+
return { success: true, action: 'type', text };
|
|
128
|
+
}
|
|
129
|
+
if (PLATFORM === 'win32') {
|
|
130
|
+
spawnSync('powershell', ['-Command',
|
|
131
|
+
'[System.Windows.Forms.SendKeys]::SendWait("' + text.replace(/[{}()^+% ~]/g, '{$&}') + '")'
|
|
132
|
+
], { timeout: 5000 });
|
|
133
|
+
return { success: true, action: 'type', text };
|
|
46
134
|
}
|
|
135
|
+
spawnSync('xdotool', ['type', text], { timeout: 5000 });
|
|
47
136
|
return { success: true, action: 'type', text };
|
|
48
137
|
}
|
|
49
138
|
|
|
50
139
|
if (action === 'keypress') {
|
|
51
140
|
if (!key) return { success: false, error: 'key gerekli' };
|
|
52
141
|
if (PLATFORM === 'darwin') {
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
142
|
+
const acc = checkAccessibility();
|
|
143
|
+
if (!acc) return { success: false, error: 'Accessibility izni gerekli' };
|
|
144
|
+
|
|
145
|
+
const parts = key.toLowerCase().split('+').map(p => p.trim());
|
|
146
|
+
const mods = [];
|
|
147
|
+
let actualKey = '';
|
|
148
|
+
for (const p of parts) {
|
|
149
|
+
if (MODIFIER_MAP[p]) mods.push(MODIFIER_MAP[p]);
|
|
150
|
+
else actualKey = p;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (KEY_MAP_DARWIN[actualKey]) {
|
|
154
|
+
const keyName = KEY_MAP_DARWIN[actualKey];
|
|
155
|
+
const usingClause = mods.length > 0 ? ' using {' + mods.join(', ') + '}' : '';
|
|
156
|
+
const r = osaScript('tell application "System Events" to keystroke ' + keyName + usingClause);
|
|
157
|
+
if (!r.success) return r;
|
|
158
|
+
} else if (actualKey) {
|
|
159
|
+
const usingClause = mods.length > 0 ? ' using {' + mods.join(', ') + '}' : '';
|
|
160
|
+
const r = osaScript('tell application "System Events" to keystroke "' + escapeText(actualKey) + '"' + usingClause);
|
|
161
|
+
if (!r.success) return r;
|
|
162
|
+
} else {
|
|
163
|
+
if (mods.length > 0) {
|
|
164
|
+
return { success: false, error: 'Modifier-only keypress not supported. Provide a key with modifiers (e.g. cmd+q).' };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return { success: true, action: 'keypress', key };
|
|
61
168
|
}
|
|
169
|
+
if (PLATFORM === 'win32') {
|
|
170
|
+
const keyMap = {
|
|
171
|
+
enter: '{ENTER}', tab: '{TAB}', escape: '{ESC}', up: '{UP}', down: '{DOWN}',
|
|
172
|
+
left: '{LEFT}', right: '{RIGHT}', backspace: '{BACKSPACE}', delete: '{DELETE}',
|
|
173
|
+
home: '{HOME}', end: '{END}', pageup: '{PGUP}', pagedown: '{PGDN}',
|
|
174
|
+
};
|
|
175
|
+
spawnSync('powershell', ['-Command',
|
|
176
|
+
'[System.Windows.Forms.SendKeys]::SendWait("' + (keyMap[key.toLowerCase()] || key) + '")'
|
|
177
|
+
], { timeout: 5000 });
|
|
178
|
+
return { success: true, action: 'keypress', key };
|
|
179
|
+
}
|
|
180
|
+
spawnSync('xdotool', ['key', key], { timeout: 5000 });
|
|
62
181
|
return { success: true, action: 'keypress', key };
|
|
63
182
|
}
|
|
64
183
|
|
|
65
184
|
if (action === 'mouse_move') {
|
|
66
185
|
if (typeof x !== 'number' || typeof y !== 'number') return { success: false, error: 'x ve y gerekli' };
|
|
67
186
|
if (PLATFORM === 'darwin') {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
187
|
+
const acc = checkAccessibility();
|
|
188
|
+
if (!acc) return { success: false, error: 'Accessibility izni gerekli' };
|
|
189
|
+
const r = osaScript('tell application "System Events" to set position of mouse to {' + x + ', ' + y + '}');
|
|
190
|
+
if (!r.success) return r;
|
|
191
|
+
return { success: true, action: 'mouse_move', x, y };
|
|
192
|
+
}
|
|
193
|
+
if (PLATFORM === 'win32') {
|
|
194
|
+
spawnSync('powershell', ['-Command',
|
|
195
|
+
'[System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(' + x + ', ' + y + ')'
|
|
196
|
+
], { timeout: 5000 });
|
|
197
|
+
return { success: true, action: 'mouse_move', x, y };
|
|
73
198
|
}
|
|
199
|
+
spawnSync('xdotool', ['mousemove', String(x), String(y)], { timeout: 5000 });
|
|
74
200
|
return { success: true, action: 'mouse_move', x, y };
|
|
75
201
|
}
|
|
76
202
|
|
|
77
203
|
if (action === 'mouse_position') {
|
|
78
204
|
if (PLATFORM === 'darwin') {
|
|
79
|
-
const
|
|
80
|
-
|
|
205
|
+
const r = osaScript('tell application "System Events" to return position of mouse');
|
|
206
|
+
if (!r.success) return r;
|
|
207
|
+
const [mx, my] = r.data.trim().split(', ').map(Number);
|
|
81
208
|
return { success: true, x: mx, y: my };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
const mx = parseInt(out.match(/x:(\d+)/)?.[1] || '0');
|
|
89
|
-
const my = parseInt(out.match(/y:(\d+)/)?.[1] || '0');
|
|
209
|
+
}
|
|
210
|
+
if (PLATFORM === 'win32') {
|
|
211
|
+
const result = spawnSync('powershell', ['-Command',
|
|
212
|
+
'[System.Windows.Forms.Cursor]::Position.X.ToString() + ", " + [System.Windows.Forms.Cursor]::Position.Y.ToString()'
|
|
213
|
+
], { timeout: 5000, encoding: 'utf8' });
|
|
214
|
+
const [mx, my] = result.stdout.trim().split(', ').map(Number);
|
|
90
215
|
return { success: true, x: mx, y: my };
|
|
91
216
|
}
|
|
217
|
+
const result = spawnSync('xdotool', ['getmouselocation'], { timeout: 5000, encoding: 'utf8' });
|
|
218
|
+
const mx = parseInt(result.stdout.match(/x:(\d+)/)?.[1] || '0');
|
|
219
|
+
const my = parseInt(result.stdout.match(/y:(\d+)/)?.[1] || '0');
|
|
220
|
+
return { success: true, x: mx, y: my };
|
|
92
221
|
}
|
|
93
222
|
|
|
94
223
|
if (action === 'scroll') {
|
|
95
224
|
if (typeof y !== 'number') return { success: false, error: 'y (pixels) gerekli' };
|
|
96
225
|
if (PLATFORM === 'darwin') {
|
|
97
|
-
|
|
98
|
-
return { success:
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
226
|
+
const acc = checkAccessibility();
|
|
227
|
+
if (!acc) return { success: false, error: 'Accessibility izni gerekli' };
|
|
228
|
+
const direction = y > 0 ? 'up' : 'down';
|
|
229
|
+
const times = Math.abs(Math.ceil(y / 40));
|
|
230
|
+
const r = osaScript('tell application "System Events" to repeat ' + times + ' times\n key code 125\nend repeat');
|
|
231
|
+
if (!r.success) return r;
|
|
232
|
+
|
|
233
|
+
return { success: true, action: 'scroll', y, note: 'Scrolled ' + direction + ' ' + times + ' steps' };
|
|
234
|
+
}
|
|
235
|
+
spawnSync('xdotool', ['click', y < 0 ? '4' : '5', '--repeat', String(Math.abs(Math.ceil(y / 50)))], { timeout: 5000 });
|
|
236
|
+
return { success: true, action: 'scroll', y };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (action === 'drag') {
|
|
240
|
+
if (typeof x !== 'number' || typeof y !== 'number') return { success: false, error: 'x ve y (baslangic) gerekli' };
|
|
241
|
+
const x2 = params.x2, y2 = params.y2;
|
|
242
|
+
if (typeof x2 !== 'number' || typeof y2 !== 'number') return { success: false, error: 'x2 ve y2 (bitis) gerekli' };
|
|
243
|
+
if (PLATFORM === 'darwin') {
|
|
244
|
+
const acc = checkAccessibility();
|
|
245
|
+
if (!acc) return { success: false, error: 'Accessibility izni gerekli' };
|
|
246
|
+
const r = osaScript('tell application "System Events"\n set mousePos to {' + x + ', ' + y + '}\n set mousePos2 to {' + x2 + ', ' + y2 + '}\n set position of mouse to mousePos\n delay 0.1\n mouse down\n set position of mouse to mousePos2\n delay 0.1\n mouse up\nend tell');
|
|
247
|
+
if (!r.success) return r;
|
|
248
|
+
return { success: true, action: 'drag', from: { x, y }, to: { x: x2, y: y2 } };
|
|
249
|
+
}
|
|
250
|
+
if (PLATFORM === 'linux') {
|
|
251
|
+
spawnSync('xdotool', ['mousemove', String(x), String(y), 'mousedown', '1', 'mousemove', String(x2), String(y2), 'mouseup', '1'], { timeout: 5000 });
|
|
252
|
+
return { success: true, action: 'drag', from: { x, y }, to: { x: x2, y: y2 } };
|
|
102
253
|
}
|
|
254
|
+
return { success: false, error: 'drag only supported on macOS and Linux' };
|
|
103
255
|
}
|
|
104
256
|
|
|
105
257
|
if (action === 'info') {
|
|
106
258
|
const displays = [];
|
|
107
259
|
try {
|
|
108
260
|
if (PLATFORM === 'darwin') {
|
|
109
|
-
const
|
|
110
|
-
for (const line of
|
|
261
|
+
const result = spawnSync('system_profiler', ['SPDisplaysDataType'], { timeout: 5000, encoding: 'utf8' });
|
|
262
|
+
for (const line of result.stdout.split('\n')) {
|
|
111
263
|
const m = line.match(/(\d+) x (\d+)/);
|
|
112
264
|
if (m) displays.push({ width: parseInt(m[1]), height: parseInt(m[2]) });
|
|
113
265
|
}
|
|
114
266
|
}
|
|
115
267
|
} catch {}
|
|
116
|
-
return { success: true, platform: PLATFORM, displays: displays.length > 0 ? displays : undefined
|
|
268
|
+
return { success: true, platform: PLATFORM, displays: displays.length > 0 ? displays : undefined };
|
|
117
269
|
}
|
|
118
270
|
|
|
119
|
-
return { success: false, error: 'Gecersiz action: ' + action + ' (screenshot, click, type, keypress, mouse_move, mouse_position, scroll, info)' };
|
|
271
|
+
return { success: false, error: 'Gecersiz action: ' + action + ' (screenshot, click, type, keypress, mouse_move, mouse_position, scroll, drag, info)' };
|
|
120
272
|
}
|
|
121
273
|
|
|
122
274
|
module.exports = {
|
|
123
275
|
name: 'computer_use',
|
|
124
|
-
description: 'GUI otomasyonu: screenshot, click, type, keypress, mouse_move, mouse_position, scroll, info. macOS/Windows/Linux.',
|
|
276
|
+
description: 'GUI otomasyonu: screenshot, click, type, keypress, mouse_move, mouse_position, scroll, drag, info. macOS/Windows/Linux.',
|
|
125
277
|
inputSchema: {
|
|
126
278
|
type: 'object',
|
|
127
279
|
properties: {
|
|
128
|
-
action: { type: 'string', description: 'screenshot, click, type, keypress, mouse_move, mouse_position, scroll, info', enum: ['screenshot', 'click', 'type', 'keypress', 'mouse_move', 'mouse_position', 'scroll', 'info'] },
|
|
280
|
+
action: { type: 'string', description: 'screenshot, click, type, keypress, mouse_move, mouse_position, scroll, drag, info', enum: ['screenshot', 'click', 'type', 'keypress', 'mouse_move', 'mouse_position', 'scroll', 'drag', 'info'] },
|
|
129
281
|
x: { type: 'number', description: 'X koordinati' },
|
|
130
282
|
y: { type: 'number', description: 'Y koordinati' },
|
|
131
283
|
button: { type: 'string', description: 'Fare tusu: left, right, middle (default: left)' },
|
|
132
284
|
clicks: { type: 'number', description: 'Tiklama sayisi (default: 1)' },
|
|
133
|
-
key: { type: 'string', description: '(keypress) Tus adi: enter, tab, escape, up, down, left, right, backspace, delete' },
|
|
285
|
+
key: { type: 'string', description: '(keypress) Tus adi veya kombinasyon: enter, tab, escape, up, down, left, right, backspace, delete, cmd+q, cmd+shift+z, alt+space' },
|
|
286
|
+
x2: { type: 'number', description: '(drag) Bitis X koordinati' },
|
|
287
|
+
y2: { type: 'number', description: '(drag) Bitis Y koordinati' },
|
|
134
288
|
text: { type: 'string', description: '(type) Yazilacak metin' },
|
|
135
|
-
query: { type: 'string', description: 'Arama sorgusu' },
|
|
136
289
|
file: { type: 'string', description: '(screenshot) Kayit dosyasi' },
|
|
137
290
|
},
|
|
138
291
|
required: ['action'],
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sub_agent — Spawn a sub-agent for delegated sub-tasks
|
|
3
|
+
*
|
|
4
|
+
* Creates a child agent with its own LLM call to handle a specific sub-task.
|
|
5
|
+
* Returns the sub-agent's response. Useful for parallel research, complex
|
|
6
|
+
* sub-problems, or when a focused agent is better than the main loop.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const https = require('https');
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const os = require('os');
|
|
13
|
+
|
|
14
|
+
function loadConfig() {
|
|
15
|
+
try { return JSON.parse(fs.readFileSync(path.join(os.homedir(), '.natureco', 'config.json'), 'utf8')); } catch { return {}; }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function isMiniMax(url) { return url && (url.includes('minimax.io') || url.includes('minimaxi.com') || url.includes('minimax.cn')); }
|
|
19
|
+
function isGemini(url) { return url && (url.includes('generativelanguage.googleapis.com') || url.includes('gemini')); }
|
|
20
|
+
|
|
21
|
+
function apiCall(providerUrl, apiKey, body) {
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
const base = providerUrl.replace(/\/+$/, '');
|
|
24
|
+
const endpoint = isMiniMax(base)
|
|
25
|
+
? base + '/v1/text/chatcompletion_v2'
|
|
26
|
+
: isGemini(base)
|
|
27
|
+
? base + '/openai/chat/completions'
|
|
28
|
+
: base + '/chat/completions';
|
|
29
|
+
const req = https.request(endpoint, {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: { 'Authorization': 'Bearer ' + apiKey, 'Content-Type': 'application/json' },
|
|
32
|
+
timeout: 120000,
|
|
33
|
+
}, (res) => {
|
|
34
|
+
let data = '';
|
|
35
|
+
res.on('data', c => data += c);
|
|
36
|
+
res.on('end', () => {
|
|
37
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
38
|
+
try { resolve(JSON.parse(data)); } catch { reject(new Error('Parse error')); }
|
|
39
|
+
} else reject(new Error('HTTP ' + res.statusCode + ': ' + data.slice(0, 300)));
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
req.on('error', reject);
|
|
43
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('Timeout')); });
|
|
44
|
+
req.write(JSON.stringify(body));
|
|
45
|
+
req.end();
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const name = 'sub_agent';
|
|
50
|
+
const description = 'Spawn a sub-agent to handle a specific sub-task independently. Returns the sub-agent\'s response. Use for parallel research, focused debugging, or complex sub-problems.';
|
|
51
|
+
const parameters = {
|
|
52
|
+
type: 'object',
|
|
53
|
+
properties: {
|
|
54
|
+
task: { type: 'string', description: 'The sub-task for the sub-agent to complete' },
|
|
55
|
+
context: { type: 'string', description: 'Additional context or background information' },
|
|
56
|
+
model: { type: 'string', description: 'Override model for this sub-agent (default: main config model)' },
|
|
57
|
+
temperature: { type: 'number', description: 'Temperature 0-1 (default: 0.3)' },
|
|
58
|
+
maxTokens: { type: 'number', description: 'Max tokens for response (default: 2000)' },
|
|
59
|
+
},
|
|
60
|
+
required: ['task'],
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
async function execute(params) {
|
|
64
|
+
const cfg = loadConfig();
|
|
65
|
+
const providerUrl = cfg.providerUrl;
|
|
66
|
+
const providerApiKey = cfg.providerApiKey;
|
|
67
|
+
const model = params.model || cfg.providerModel || 'default';
|
|
68
|
+
|
|
69
|
+
if (!providerUrl || !providerApiKey) {
|
|
70
|
+
return JSON.stringify({ success: false, error: 'Provider not configured. Run natureco setup first.' });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const systemContent = 'Sen bir alt-agentsin. Verilen gorevi tamamlamak icin elinden geleni yap. Kisa ve oz yanit ver.'
|
|
74
|
+
+ (params.context ? '\n\nContext:\n' + params.context : '');
|
|
75
|
+
|
|
76
|
+
const body = {
|
|
77
|
+
model,
|
|
78
|
+
messages: [
|
|
79
|
+
{ role: 'system', content: systemContent },
|
|
80
|
+
{ role: 'user', content: params.task },
|
|
81
|
+
],
|
|
82
|
+
stream: false,
|
|
83
|
+
temperature: params.temperature ?? 0.3,
|
|
84
|
+
max_tokens: params.maxTokens || 2000,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const result = await apiCall(providerUrl, providerApiKey, body);
|
|
89
|
+
const reply = result.choices?.[0]?.message?.content || '';
|
|
90
|
+
return JSON.stringify({ success: true, response: reply, model });
|
|
91
|
+
} catch (e) {
|
|
92
|
+
return JSON.stringify({ success: false, error: e.message });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = { name, description, parameters, execute };
|
package/src/utils/tools.js
CHANGED
|
@@ -68,6 +68,7 @@ const EMOJI_MAP = {
|
|
|
68
68
|
google_meet: '📹',
|
|
69
69
|
// Orchestrator
|
|
70
70
|
workflow: '⚙️',
|
|
71
|
+
social_open: '🔗', youtube_ac: '🎬', memory_provider: '🗄️',
|
|
71
72
|
};
|
|
72
73
|
|
|
73
74
|
// ── Toolset grouping ─────────────────────────────────────────────────────
|
|
@@ -122,6 +123,8 @@ const TOOLSET_MAP = {
|
|
|
122
123
|
async_delegation: 'agent', blueprint: 'planning', workflow: 'orchestrator',
|
|
123
124
|
spotify: 'media', homeassistant: 'iot', microsoft_graph: 'office',
|
|
124
125
|
computer_use: 'automation', google_meet: 'communication',
|
|
126
|
+
social_open: 'communication', youtube_ac: 'media',
|
|
127
|
+
sub_agent: 'agent', memory_provider: 'memory',
|
|
125
128
|
};
|
|
126
129
|
|
|
127
130
|
// ── check_fn'ler (tool availability kontrolleri) ────────────────────────
|
|
@@ -227,16 +230,17 @@ function loadToolDefinitions() {
|
|
|
227
230
|
}
|
|
228
231
|
|
|
229
232
|
const ALIAS_MAP = {
|
|
230
|
-
'brave_search': '
|
|
231
|
-
'google_search': '
|
|
233
|
+
'brave_search': 'duckduckgo_search', 'brave-web-search': 'duckduckgo_search',
|
|
234
|
+
'google_search': 'duckduckgo_search', 'web_search': 'duckduckgo_search',
|
|
232
235
|
'browse': 'browser', 'shell': 'bash', 'bash_command': 'bash',
|
|
233
236
|
'execute_command': 'bash', 'run_command': 'bash',
|
|
237
|
+
'http': 'http_request',
|
|
234
238
|
};
|
|
235
239
|
|
|
236
240
|
const BLOCKED_NAMES = new Set([
|
|
237
241
|
'brave_search', 'brave-web-search', 'google_search', 'web_search',
|
|
238
242
|
'browse', 'open', 'search', 'shell', 'bash_command', 'execute_command',
|
|
239
|
-
'run_command', 'sql', 'query', 'lookup',
|
|
243
|
+
'run_command', 'sql', 'query', 'lookup', 'http',
|
|
240
244
|
]);
|
|
241
245
|
|
|
242
246
|
// ── check_fn TTL cache (Hermes-style, ~30s) ────────────────────────────
|