lua-cli 1.3.2-alpha.0 ā 1.3.2-alpha.2
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/dist/commands/compile.js +227 -165
- package/dist/commands/dev.js +117 -114
- package/dist/commands/test.js +122 -130
- package/dist/services/api.d.ts +4 -4
- package/dist/services/api.js +8 -4
- package/dist/skill.d.ts +16 -1
- package/dist/skill.js +49 -0
- package/dist/types/index.d.ts +3 -3
- package/dist/user-data-api.d.ts +1 -0
- package/dist/user-data-api.js +9 -4
- package/dist/utils/files.js +33 -5
- package/dist/utils/sandbox.d.ts +96 -0
- package/dist/utils/sandbox.js +161 -0
- package/dist/web/app.css +274 -43
- package/dist/web/app.js +13 -13
- package/dist/web/tools-page.css +70 -53
- package/package.json +1 -1
- package/template/lua.skill.yaml +16 -0
- package/template/package-lock.json +9 -1
- package/template/package.json +3 -3
- package/template/src/index.ts +3 -13
- package/template/src/tools/CreatePostTool.ts +15 -23
- package/template/src/tools/GetWeatherTool.ts +22 -23
- package/template/src/tools/UserDataTool.ts +56 -0
- package/template/src/services/MathService.ts +0 -61
- package/template/src/tools/AdvancedMathTool.ts +0 -82
- package/template/src/tools/CalculatorTool.ts +0 -65
- package/template/src/tools/GetUserDataTool.ts +0 -38
- package/template/tools/UserPreferencesTool.ts +0 -73
package/dist/commands/dev.js
CHANGED
|
@@ -5,6 +5,7 @@ import inquirer from 'inquirer';
|
|
|
5
5
|
import { compileCommand } from './compile.js';
|
|
6
6
|
import { checkApiKey, loadApiKey } from '../services/auth.js';
|
|
7
7
|
import { ApiService } from '../services/api.js';
|
|
8
|
+
import { executeTool, createBroadcastConsole } from '../utils/sandbox.js';
|
|
8
9
|
import { readSkillConfig, updateSkillYamlPersona } from '../utils/files.js';
|
|
9
10
|
import { withErrorHandling, clearPromptLines, writeProgress, writeSuccess } from '../utils/cli.js';
|
|
10
11
|
import keytar from 'keytar';
|
|
@@ -190,6 +191,14 @@ function createChatServer(apiKey, agentId, skillId, sandboxId, port = 3000) {
|
|
|
190
191
|
res.end(JSON.stringify({ success: false, error: 'Tool not found' }));
|
|
191
192
|
return;
|
|
192
193
|
}
|
|
194
|
+
// Extract environment variables from YAML config
|
|
195
|
+
const config = readSkillConfig();
|
|
196
|
+
const envVars = {};
|
|
197
|
+
if (config?.skill?.env) {
|
|
198
|
+
for (const [key, value] of Object.entries(config.skill.env)) {
|
|
199
|
+
envVars[key] = value;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
193
202
|
// Decompress and execute the tool
|
|
194
203
|
const { gunzipSync } = await import('zlib');
|
|
195
204
|
const { Buffer } = await import('buffer');
|
|
@@ -200,64 +209,22 @@ function createChatServer(apiKey, agentId, skillId, sandboxId, port = 3000) {
|
|
|
200
209
|
return gunzipSync(buffer).toString('utf8');
|
|
201
210
|
}
|
|
202
211
|
const toolCode = decompressCode(tool.execute);
|
|
203
|
-
// Create
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
exports: {},
|
|
220
|
-
// Web APIs
|
|
221
|
-
fetch: globalThis.fetch,
|
|
222
|
-
URLSearchParams: globalThis.URLSearchParams,
|
|
223
|
-
URL: globalThis.URL,
|
|
224
|
-
Headers: globalThis.Headers,
|
|
225
|
-
Request: globalThis.Request,
|
|
226
|
-
Response: globalThis.Response,
|
|
227
|
-
// Additional globals
|
|
228
|
-
Object,
|
|
229
|
-
Array,
|
|
230
|
-
String,
|
|
231
|
-
Number,
|
|
232
|
-
Boolean,
|
|
233
|
-
Date,
|
|
234
|
-
Math,
|
|
235
|
-
JSON,
|
|
236
|
-
Error,
|
|
237
|
-
TypeError,
|
|
238
|
-
ReferenceError,
|
|
239
|
-
SyntaxError,
|
|
240
|
-
globalThis,
|
|
241
|
-
undefined: undefined,
|
|
242
|
-
null: null,
|
|
243
|
-
Infinity: Infinity,
|
|
244
|
-
NaN: NaN
|
|
245
|
-
};
|
|
246
|
-
// Create the CommonJS wrapper code
|
|
247
|
-
const commonJsWrapper = `
|
|
248
|
-
const executeFunction = ${toolCode};
|
|
249
|
-
|
|
250
|
-
// Export the function for testing
|
|
251
|
-
module.exports = async (input) => {
|
|
252
|
-
return await executeFunction(input);
|
|
253
|
-
};
|
|
254
|
-
`;
|
|
255
|
-
// Execute the code in the sandbox
|
|
256
|
-
const context = vm.createContext(sandbox);
|
|
257
|
-
vm.runInContext(commonJsWrapper, context);
|
|
258
|
-
// Get the exported function and execute it
|
|
259
|
-
const executeFunction = context.module.exports;
|
|
260
|
-
const result = await executeFunction(inputs);
|
|
212
|
+
// Create custom console that captures output and sends via WebSocket
|
|
213
|
+
const customConsole = createBroadcastConsole((logData) => {
|
|
214
|
+
wss.clients.forEach((client) => {
|
|
215
|
+
if (client.readyState === 1) { // WebSocket.OPEN
|
|
216
|
+
client.send(JSON.stringify(logData));
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
// Execute the tool using the common utility
|
|
221
|
+
const result = await executeTool({
|
|
222
|
+
toolCode,
|
|
223
|
+
inputs,
|
|
224
|
+
apiKey,
|
|
225
|
+
agentId,
|
|
226
|
+
customConsole
|
|
227
|
+
});
|
|
261
228
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
262
229
|
res.end(JSON.stringify({
|
|
263
230
|
success: true,
|
|
@@ -328,22 +295,44 @@ module.exports = async (input) => {
|
|
|
328
295
|
res.writeHead(404);
|
|
329
296
|
res.end('Not Found');
|
|
330
297
|
});
|
|
331
|
-
// Create WebSocket server for
|
|
298
|
+
// Create WebSocket server for log streaming
|
|
332
299
|
const wss = new WebSocketServer({ server });
|
|
333
300
|
wss.on('connection', (ws) => {
|
|
334
|
-
console.log('WebSocket client connected for
|
|
301
|
+
console.log('WebSocket client connected for log streaming');
|
|
335
302
|
ws.on('close', () => {
|
|
336
303
|
console.log('WebSocket client disconnected');
|
|
337
304
|
});
|
|
338
305
|
ws.on('error', (error) => {
|
|
339
306
|
console.error('WebSocket error:', error);
|
|
340
307
|
});
|
|
308
|
+
// Send initial connection message
|
|
309
|
+
ws.send(JSON.stringify({
|
|
310
|
+
type: 'log',
|
|
311
|
+
subType: 'info',
|
|
312
|
+
message: 'Connected to CLI dev server',
|
|
313
|
+
timestamp: new Date().toISOString()
|
|
314
|
+
}));
|
|
341
315
|
});
|
|
342
316
|
server.listen(port, () => {
|
|
343
317
|
console.log('Chat interface available at: http://localhost:' + port);
|
|
344
|
-
console.log('
|
|
318
|
+
console.log('Log streaming WebSocket available at: ws://localhost:' + port);
|
|
345
319
|
});
|
|
346
|
-
|
|
320
|
+
// Function to broadcast logs to all connected clients
|
|
321
|
+
const broadcastLog = (message, subType = 'info') => {
|
|
322
|
+
const logMessage = {
|
|
323
|
+
type: 'log',
|
|
324
|
+
subType,
|
|
325
|
+
message,
|
|
326
|
+
timestamp: new Date().toISOString(),
|
|
327
|
+
id: Date.now().toString()
|
|
328
|
+
};
|
|
329
|
+
wss.clients.forEach((client) => {
|
|
330
|
+
if (client.readyState === 1) { // WebSocket.OPEN
|
|
331
|
+
client.send(JSON.stringify(logMessage));
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
};
|
|
335
|
+
return { server, wss, broadcastLog };
|
|
347
336
|
}
|
|
348
337
|
// Function to update existing sandbox version
|
|
349
338
|
export async function updateDevVersion(apiKey, agentId, skillId, sandboxVersionId, versionData) {
|
|
@@ -415,10 +404,6 @@ export async function pushDevVersion(apiKey, agentId, skillId, versionData) {
|
|
|
415
404
|
};
|
|
416
405
|
}
|
|
417
406
|
}
|
|
418
|
-
function readConfigSkillName() {
|
|
419
|
-
const config = readSkillConfig();
|
|
420
|
-
return config?.skill?.name || null;
|
|
421
|
-
}
|
|
422
407
|
function readConfigVersion() {
|
|
423
408
|
const config = readSkillConfig();
|
|
424
409
|
return config?.skill?.version || null;
|
|
@@ -434,18 +419,21 @@ function readDeployJson() {
|
|
|
434
419
|
// Function to push to sandbox (extracted for reuse)
|
|
435
420
|
async function pushToSandbox(apiKey, agentId, skillId, deployData, isInitial = false) {
|
|
436
421
|
const sandboxSkillId = await getSandboxSkillId();
|
|
437
|
-
// Read skill name
|
|
438
|
-
const
|
|
439
|
-
const
|
|
422
|
+
// Read skill name and environment variables from config
|
|
423
|
+
const config = readSkillConfig();
|
|
424
|
+
const skillName = config?.skill?.name || deployData.name || 'Unknown Skill';
|
|
425
|
+
const envVars = config?.skill?.env || {};
|
|
426
|
+
const payloadWithNameAndEnv = {
|
|
440
427
|
...deployData,
|
|
441
|
-
name: skillName
|
|
428
|
+
name: skillName,
|
|
429
|
+
env: envVars
|
|
442
430
|
};
|
|
443
431
|
if (sandboxSkillId) {
|
|
444
432
|
// Try to update existing sandbox version
|
|
445
433
|
if (!isInitial) {
|
|
446
434
|
writeProgress("š Updating existing sandbox version...");
|
|
447
435
|
}
|
|
448
|
-
const updateResult = await updateDevVersion(apiKey, agentId, skillId, sandboxSkillId,
|
|
436
|
+
const updateResult = await updateDevVersion(apiKey, agentId, skillId, sandboxSkillId, payloadWithNameAndEnv);
|
|
449
437
|
if (updateResult.success && updateResult.data) {
|
|
450
438
|
if (!isInitial) {
|
|
451
439
|
writeSuccess(`ā
Version ${updateResult.data.version} updated in sandbox successfully`);
|
|
@@ -468,7 +456,7 @@ async function pushToSandbox(apiKey, agentId, skillId, deployData, isInitial = f
|
|
|
468
456
|
if (!isInitial) {
|
|
469
457
|
writeProgress("š Creating new sandbox version...");
|
|
470
458
|
}
|
|
471
|
-
const result = await pushDevVersion(apiKey, agentId, skillId,
|
|
459
|
+
const result = await pushDevVersion(apiKey, agentId, skillId, payloadWithNameAndEnv);
|
|
472
460
|
if (result.success && result.data) {
|
|
473
461
|
// Store the new sandbox skill ID
|
|
474
462
|
await setSandboxSkillId(result.data.skillId);
|
|
@@ -571,26 +559,37 @@ export async function devCommand() {
|
|
|
571
559
|
}
|
|
572
560
|
// Start web server for chat interface
|
|
573
561
|
const chatPort = 3000;
|
|
574
|
-
const { server, wss } = createChatServer(apiKey, agentId, skillId, sandboxSkillId, chatPort);
|
|
562
|
+
const { server, wss, broadcastLog } = createChatServer(apiKey, agentId, skillId, sandboxSkillId, chatPort);
|
|
575
563
|
// Open browser to chat interface
|
|
576
564
|
try {
|
|
577
565
|
await open(`http://localhost:${chatPort}`);
|
|
578
566
|
writeSuccess("š Chat interface opened in your browser");
|
|
567
|
+
broadcastLog("š Chat interface opened in your browser", 'info');
|
|
579
568
|
}
|
|
580
569
|
catch (error) {
|
|
581
570
|
writeSuccess(`š Chat interface available at: http://localhost:${chatPort}`);
|
|
571
|
+
broadcastLog(`š Chat interface available at: http://localhost:${chatPort}`, 'info');
|
|
582
572
|
}
|
|
583
573
|
// Start file watching
|
|
584
574
|
writeSuccess("š Watching for file changes... (Press Ctrl+C to stop)");
|
|
575
|
+
broadcastLog("š Watching for file changes... (Press Ctrl+C to stop)", 'info');
|
|
585
576
|
let isCompiling = false;
|
|
586
577
|
let pendingCompile = false;
|
|
578
|
+
let compileTimeout = null;
|
|
587
579
|
const watcher = watch(process.cwd(), { recursive: true }, async (eventType, filename) => {
|
|
588
580
|
// Ignore changes in .lua directory and other build artifacts
|
|
589
581
|
if (filename && (filename.includes('.lua/') ||
|
|
582
|
+
filename.includes('.lua\\') ||
|
|
590
583
|
filename.includes('node_modules/') ||
|
|
584
|
+
filename.includes('node_modules\\') ||
|
|
591
585
|
filename.includes('.git/') ||
|
|
586
|
+
filename.includes('.git\\') ||
|
|
592
587
|
filename.endsWith('.log') ||
|
|
593
|
-
filename.endsWith('.tmp')
|
|
588
|
+
filename.endsWith('.tmp') ||
|
|
589
|
+
filename.endsWith('.js') ||
|
|
590
|
+
filename.endsWith('.map') ||
|
|
591
|
+
filename.includes('dist/') ||
|
|
592
|
+
filename.includes('dist\\'))) {
|
|
594
593
|
return;
|
|
595
594
|
}
|
|
596
595
|
// Debounce rapid changes
|
|
@@ -598,55 +597,59 @@ export async function devCommand() {
|
|
|
598
597
|
pendingCompile = true;
|
|
599
598
|
return;
|
|
600
599
|
}
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
const updatedDeployData = readDeployJson();
|
|
609
|
-
if (!updatedDeployData) {
|
|
610
|
-
writeProgress("ā Compilation failed, skipping push");
|
|
611
|
-
return;
|
|
612
|
-
}
|
|
613
|
-
// Verify version matches
|
|
614
|
-
if (updatedDeployData.version !== version) {
|
|
615
|
-
writeProgress("ā Version mismatch, skipping push");
|
|
600
|
+
// Clear any existing timeout
|
|
601
|
+
if (compileTimeout) {
|
|
602
|
+
clearTimeout(compileTimeout);
|
|
603
|
+
}
|
|
604
|
+
// Debounce file changes with a 500ms delay
|
|
605
|
+
compileTimeout = setTimeout(async () => {
|
|
606
|
+
if (isCompiling) {
|
|
616
607
|
return;
|
|
617
608
|
}
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
writeProgress(
|
|
609
|
+
isCompiling = true;
|
|
610
|
+
pendingCompile = false;
|
|
611
|
+
try {
|
|
612
|
+
writeProgress(`š File changed: ${filename} - Compiling and pushing...`);
|
|
613
|
+
broadcastLog(`š File changed: ${filename} - Compiling and pushing...`, 'info');
|
|
614
|
+
// Compile the skill
|
|
615
|
+
await compileCommand();
|
|
616
|
+
broadcastLog("ā
Compilation completed", 'info');
|
|
617
|
+
// Read updated deploy.json
|
|
618
|
+
const updatedDeployData = readDeployJson();
|
|
619
|
+
if (!updatedDeployData) {
|
|
620
|
+
writeProgress("ā Compilation failed, skipping push");
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
// Verify version matches
|
|
624
|
+
if (updatedDeployData.version !== version) {
|
|
625
|
+
writeProgress("ā Version mismatch, skipping push");
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
// Push to sandbox
|
|
629
|
+
const pushSuccess = await pushToSandbox(apiKey, agentId, skillId, updatedDeployData, false);
|
|
630
|
+
if (!pushSuccess) {
|
|
631
|
+
writeProgress("ā Failed to push to sandbox, will retry on next change");
|
|
632
|
+
broadcastLog("ā Failed to push to sandbox, will retry on next change", 'error');
|
|
633
|
+
}
|
|
634
|
+
else {
|
|
635
|
+
writeProgress("ā
Successfully pushed to sandbox");
|
|
636
|
+
broadcastLog("ā
Successfully pushed to sandbox", 'info');
|
|
637
|
+
}
|
|
622
638
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
wss.clients.forEach((client) => {
|
|
626
|
-
if (client.readyState === 1) { // WebSocket.OPEN
|
|
627
|
-
client.send(JSON.stringify({ type: 'reload', message: 'Files changed, reloading...' }));
|
|
628
|
-
}
|
|
629
|
-
});
|
|
639
|
+
catch (error) {
|
|
640
|
+
writeProgress(`ā Error during auto-compile: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
630
641
|
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
writeProgress(`ā Error during auto-compile: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
634
|
-
}
|
|
635
|
-
finally {
|
|
636
|
-
isCompiling = false;
|
|
637
|
-
// Handle any pending compile
|
|
638
|
-
if (pendingCompile) {
|
|
639
|
-
setTimeout(() => {
|
|
640
|
-
if (!isCompiling) {
|
|
641
|
-
watcher.emit('change', 'pending', 'pending');
|
|
642
|
-
}
|
|
643
|
-
}, 100);
|
|
642
|
+
finally {
|
|
643
|
+
isCompiling = false;
|
|
644
644
|
}
|
|
645
|
-
}
|
|
645
|
+
}, 500); // 500ms debounce delay
|
|
646
646
|
});
|
|
647
647
|
// Handle graceful shutdown
|
|
648
648
|
process.on('SIGINT', () => {
|
|
649
649
|
writeSuccess("\nš Stopping file watcher...");
|
|
650
|
+
if (compileTimeout) {
|
|
651
|
+
clearTimeout(compileTimeout);
|
|
652
|
+
}
|
|
650
653
|
watcher.close();
|
|
651
654
|
process.exit(0);
|
|
652
655
|
});
|
package/dist/commands/test.js
CHANGED
|
@@ -4,11 +4,9 @@ import inquirer from "inquirer";
|
|
|
4
4
|
import { compileCommand } from "./compile.js";
|
|
5
5
|
import { gunzipSync } from "zlib";
|
|
6
6
|
import { Buffer } from "buffer";
|
|
7
|
-
import { createRequire } from "module";
|
|
8
|
-
import vm from "vm";
|
|
9
7
|
import { withErrorHandling, clearPromptLines, writeProgress, writeSuccess } from "../utils/cli.js";
|
|
10
|
-
import { UserDataApi } from "../services/api.js";
|
|
11
8
|
import { loadApiKey } from "../services/auth.js";
|
|
9
|
+
import { executeTool } from "../utils/sandbox.js";
|
|
12
10
|
import { readSkillConfig } from "../utils/files.js";
|
|
13
11
|
// Decompression utility
|
|
14
12
|
function decompressCode(compressedCode) {
|
|
@@ -40,11 +38,19 @@ export async function testCommand() {
|
|
|
40
38
|
if (!apiKey) {
|
|
41
39
|
throw new Error("No API key found. Please run 'lua auth configure' first.");
|
|
42
40
|
}
|
|
41
|
+
// Extract environment variables from YAML config
|
|
43
42
|
const config = readSkillConfig();
|
|
44
43
|
const agentId = config?.agent?.agentId;
|
|
45
44
|
if (!agentId) {
|
|
46
45
|
throw new Error("No agent ID found in lua.skill.yaml. Please run 'lua skill init' first.");
|
|
47
46
|
}
|
|
47
|
+
// Extract environment variables from YAML config
|
|
48
|
+
const envVars = {};
|
|
49
|
+
if (config?.skill?.env) {
|
|
50
|
+
for (const [key, value] of Object.entries(config.skill.env)) {
|
|
51
|
+
envVars[key] = value;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
48
54
|
// Let user select a tool using picker
|
|
49
55
|
const toolChoices = deployData.tools.map((tool) => ({
|
|
50
56
|
name: `${tool.name} - ${tool.description}`,
|
|
@@ -63,66 +69,122 @@ export async function testCommand() {
|
|
|
63
69
|
clearPromptLines(2);
|
|
64
70
|
writeProgress(`ā
Selected tool: ${selectedTool.name}`);
|
|
65
71
|
// Get input values for each required parameter using inquirer
|
|
66
|
-
|
|
72
|
+
let inputValues = {};
|
|
67
73
|
const inputSchema = selectedTool.inputSchema;
|
|
68
74
|
if (inputSchema.properties) {
|
|
69
75
|
writeProgress("\nš Enter input values:");
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
// Recursive function to generate prompts for nested objects
|
|
77
|
+
async function generatePromptsForObject(schema, prefix = '', required = []) {
|
|
78
|
+
const prompts = [];
|
|
79
|
+
const result = {};
|
|
80
|
+
for (const [key, value] of Object.entries(schema.properties || {})) {
|
|
81
|
+
const property = value;
|
|
82
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
83
|
+
const isRequired = required.includes(key);
|
|
84
|
+
if (property.type === "object" && property.properties) {
|
|
85
|
+
// Handle nested object - use fullKey to maintain proper prompt names
|
|
86
|
+
writeProgress(`\nš Entering values for ${key}:`);
|
|
87
|
+
const nestedResult = await generatePromptsForObject(property, fullKey, property.required || []);
|
|
88
|
+
// Extract the nested values from the nested result
|
|
89
|
+
result[key] = nestedResult[key] || nestedResult;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// Handle primitive types
|
|
93
|
+
let promptType = 'input';
|
|
94
|
+
let validate = undefined;
|
|
95
|
+
switch (property.type) {
|
|
96
|
+
case "string":
|
|
97
|
+
if (isRequired) {
|
|
98
|
+
validate = (input) => input.trim() !== "" || `${key} is required`;
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
case "number":
|
|
102
|
+
promptType = 'number';
|
|
103
|
+
if (isRequired) {
|
|
104
|
+
validate = (input) => !isNaN(input) || `${key} must be a valid number`;
|
|
105
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
case "boolean":
|
|
108
|
+
promptType = 'confirm';
|
|
109
|
+
break;
|
|
110
|
+
default:
|
|
111
|
+
if (isRequired) {
|
|
112
|
+
validate = (input) => input.trim() !== "" || `${key} is required`;
|
|
113
|
+
}
|
|
81
114
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
validate
|
|
115
|
+
const prompt = {
|
|
116
|
+
type: promptType,
|
|
117
|
+
name: fullKey,
|
|
118
|
+
message: `${key}${isRequired ? " (required)" : " (optional)"}:`,
|
|
119
|
+
validate: validate,
|
|
120
|
+
};
|
|
121
|
+
prompts.push(prompt);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (prompts.length > 0) {
|
|
125
|
+
const answers = await inquirer.prompt(prompts);
|
|
126
|
+
// Convert answers to proper types and structure
|
|
127
|
+
for (const [key, value] of Object.entries(answers)) {
|
|
128
|
+
const keyParts = key.split('.');
|
|
129
|
+
const propertyKey = keyParts[keyParts.length - 1];
|
|
130
|
+
// For nested properties, we need to find the property in the original schema
|
|
131
|
+
let currentSchema = inputSchema; // Use the original inputSchema
|
|
132
|
+
let currentProperty = null;
|
|
133
|
+
// Navigate through nested schemas to find the property
|
|
134
|
+
for (let i = 0; i < keyParts.length; i++) {
|
|
135
|
+
const part = keyParts[i];
|
|
136
|
+
if (currentSchema.properties && currentSchema.properties[part]) {
|
|
137
|
+
currentProperty = currentSchema.properties[part];
|
|
138
|
+
if (i < keyParts.length - 1) {
|
|
139
|
+
// Move to nested schema
|
|
140
|
+
currentSchema = currentProperty;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
87
143
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
144
|
+
if (currentProperty) {
|
|
145
|
+
let convertedValue = value;
|
|
146
|
+
switch (currentProperty.type) {
|
|
147
|
+
case "number":
|
|
148
|
+
convertedValue = parseFloat(value);
|
|
149
|
+
break;
|
|
150
|
+
case "boolean":
|
|
151
|
+
convertedValue = value;
|
|
152
|
+
break;
|
|
153
|
+
default:
|
|
154
|
+
convertedValue = value;
|
|
155
|
+
}
|
|
156
|
+
// Check if field is optional and value is empty - skip if so
|
|
157
|
+
// For nested properties, check the parent schema's required fields
|
|
158
|
+
const parentSchema = keyParts.length > 1 ? currentSchema : schema;
|
|
159
|
+
const isOptional = !parentSchema.required || !parentSchema.required.includes(propertyKey);
|
|
160
|
+
const isEmpty = convertedValue === '' || convertedValue === null || convertedValue === undefined;
|
|
161
|
+
if (isOptional && isEmpty) {
|
|
162
|
+
// Skip optional empty fields
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
// Build nested structure
|
|
166
|
+
if (keyParts.length === 1) {
|
|
167
|
+
// Top-level property
|
|
168
|
+
result[propertyKey] = convertedValue;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
// Nested property - build the nested structure
|
|
172
|
+
let current = result;
|
|
173
|
+
for (let i = 0; i < keyParts.length - 1; i++) {
|
|
174
|
+
const part = keyParts[i];
|
|
175
|
+
if (!current[part]) {
|
|
176
|
+
current[part] = {};
|
|
177
|
+
}
|
|
178
|
+
current = current[part];
|
|
179
|
+
}
|
|
180
|
+
current[propertyKey] = convertedValue;
|
|
181
|
+
}
|
|
95
182
|
}
|
|
96
|
-
}
|
|
97
|
-
inputPrompts.push({
|
|
98
|
-
type: promptType,
|
|
99
|
-
name: key,
|
|
100
|
-
message: `${key}${isRequired ? " (required)" : " (optional)"}:`,
|
|
101
|
-
validate: validate,
|
|
102
|
-
when: isRequired ? true : (answers) => {
|
|
103
|
-
// For optional fields, ask if user wants to provide a value
|
|
104
|
-
return true;
|
|
105
183
|
}
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
const answers = await inquirer.prompt(inputPrompts);
|
|
109
|
-
// Convert answers to proper types
|
|
110
|
-
for (const [key, value] of Object.entries(answers)) {
|
|
111
|
-
const property = inputSchema.properties[key];
|
|
112
|
-
switch (property.type) {
|
|
113
|
-
case "string":
|
|
114
|
-
inputValues[key] = value;
|
|
115
|
-
break;
|
|
116
|
-
case "number":
|
|
117
|
-
inputValues[key] = parseFloat(value);
|
|
118
|
-
break;
|
|
119
|
-
case "boolean":
|
|
120
|
-
inputValues[key] = value;
|
|
121
|
-
break;
|
|
122
|
-
default:
|
|
123
|
-
inputValues[key] = value;
|
|
124
184
|
}
|
|
185
|
+
return result;
|
|
125
186
|
}
|
|
187
|
+
inputValues = await generatePromptsForObject(inputSchema, '', inputSchema.required || []);
|
|
126
188
|
}
|
|
127
189
|
writeProgress("\nš Executing tool...");
|
|
128
190
|
writeProgress(`Input: ${JSON.stringify(inputValues, null, 2)}`);
|
|
@@ -130,82 +192,12 @@ export async function testCommand() {
|
|
|
130
192
|
const toolCode = decompressCode(selectedTool.execute);
|
|
131
193
|
// Execute the tool
|
|
132
194
|
try {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
return await UserDataApi.getUserData(apiKey, agentId);
|
|
140
|
-
};
|
|
141
|
-
const linkUserData = async (data) => {
|
|
142
|
-
return await UserDataApi.createUserData(apiKey, agentId, data);
|
|
143
|
-
};
|
|
144
|
-
// Create a sandbox context with require and other necessary globals
|
|
145
|
-
const sandbox = {
|
|
146
|
-
require,
|
|
147
|
-
console,
|
|
148
|
-
Buffer,
|
|
149
|
-
setTimeout,
|
|
150
|
-
setInterval,
|
|
151
|
-
clearTimeout,
|
|
152
|
-
clearInterval,
|
|
153
|
-
process,
|
|
154
|
-
global: globalThis,
|
|
155
|
-
__dirname: process.cwd(),
|
|
156
|
-
__filename: path.join(process.cwd(), 'index.ts'),
|
|
157
|
-
module: { exports: {} },
|
|
158
|
-
exports: {},
|
|
159
|
-
// Web APIs
|
|
160
|
-
fetch: globalThis.fetch,
|
|
161
|
-
URLSearchParams: globalThis.URLSearchParams,
|
|
162
|
-
URL: globalThis.URL,
|
|
163
|
-
Headers: globalThis.Headers,
|
|
164
|
-
Request: globalThis.Request,
|
|
165
|
-
Response: globalThis.Response,
|
|
166
|
-
// Additional Node.js globals that might be needed
|
|
167
|
-
Object,
|
|
168
|
-
Array,
|
|
169
|
-
String,
|
|
170
|
-
Number,
|
|
171
|
-
Boolean,
|
|
172
|
-
Date,
|
|
173
|
-
Math,
|
|
174
|
-
JSON,
|
|
175
|
-
Error,
|
|
176
|
-
TypeError,
|
|
177
|
-
ReferenceError,
|
|
178
|
-
SyntaxError,
|
|
179
|
-
// Node.js specific globals
|
|
180
|
-
globalThis,
|
|
181
|
-
// Additional globals that might be referenced
|
|
182
|
-
undefined: undefined,
|
|
183
|
-
null: null,
|
|
184
|
-
Infinity: Infinity,
|
|
185
|
-
NaN: NaN,
|
|
186
|
-
user: {
|
|
187
|
-
data: {
|
|
188
|
-
update: updateUserData,
|
|
189
|
-
get: getUserData,
|
|
190
|
-
create: linkUserData
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
// Create the CommonJS wrapper code
|
|
195
|
-
const commonJsWrapper = `
|
|
196
|
-
const executeFunction = ${toolCode};
|
|
197
|
-
|
|
198
|
-
// Export the function for testing
|
|
199
|
-
module.exports = async (input) => {
|
|
200
|
-
return await executeFunction(input);
|
|
201
|
-
};
|
|
202
|
-
`;
|
|
203
|
-
// Execute the code in the sandbox
|
|
204
|
-
const context = vm.createContext(sandbox);
|
|
205
|
-
vm.runInContext(commonJsWrapper, context);
|
|
206
|
-
// Get the exported function
|
|
207
|
-
const executeFunction = context.module.exports;
|
|
208
|
-
const result = await executeFunction(inputValues);
|
|
195
|
+
const result = await executeTool({
|
|
196
|
+
toolCode,
|
|
197
|
+
inputs: inputValues,
|
|
198
|
+
apiKey,
|
|
199
|
+
agentId
|
|
200
|
+
});
|
|
209
201
|
writeSuccess("ā
Tool execution successful!");
|
|
210
202
|
console.log(`Output: ${JSON.stringify(result, null, 2)}`);
|
|
211
203
|
}
|
package/dist/services/api.d.ts
CHANGED
|
@@ -184,10 +184,10 @@ export declare class ToolApi {
|
|
|
184
184
|
static patchTool(url: string, data: any, apiKey: string): Promise<ApiResponse<any>>;
|
|
185
185
|
}
|
|
186
186
|
export declare class UserDataApi {
|
|
187
|
-
static getUserData(apiKey: string, agentId: string): Promise<
|
|
188
|
-
static createUserData(apiKey: string, agentId: string, data: any): Promise<
|
|
189
|
-
static updateUserData(apiKey: string, agentId: string, data: any): Promise<ApiResponse<
|
|
190
|
-
static deleteUserData(apiKey: string, agentId: string): Promise<ApiResponse<
|
|
187
|
+
static getUserData(apiKey: string, agentId: string): Promise<any>;
|
|
188
|
+
static createUserData(apiKey: string, agentId: string, data: any): Promise<any>;
|
|
189
|
+
static updateUserData(apiKey: string, agentId: string, data: any): Promise<ApiResponse<any>>;
|
|
190
|
+
static deleteUserData(apiKey: string, agentId: string): Promise<ApiResponse<any>>;
|
|
191
191
|
}
|
|
192
192
|
/**
|
|
193
193
|
* Main API service that exports all API classes
|