lua-cli 1.1.4-beta.2 โ 1.2.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 +32 -0
- package/README.md +183 -8
- package/dist/commands/deploy.js +69 -10
- package/dist/commands/test.js +62 -11
- package/dist/skill.d.ts +1 -2
- package/dist/skill.js +1 -2
- package/package.json +8 -3
- package/template/.lua/deploy.json +53 -3
- package/template/API.md +604 -0
- package/template/DEVELOPER.md +771 -0
- package/template/QUICKSTART.md +170 -0
- package/template/README.md +477 -0
- package/template/index.ts +40 -16
- package/template/services/GetWeather.ts +35 -3
- package/template/services/MathService.ts +61 -0
- package/template/tools/AdvancedMathTool.ts +82 -0
- package/template/tools/CalculatorTool.ts +65 -0
- package/template/tools/CreatePostTool.ts +15 -3
- package/template/tools/GetUserDataTool.ts +15 -3
- package/template/tools/GetWeatherTool.ts +18 -5
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Quick Start Guide
|
|
2
|
+
|
|
3
|
+
Get up and running with Lua CLI in 5 minutes!
|
|
4
|
+
|
|
5
|
+
## ๐ Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g lua-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## ๐ฆ Create Your First Skill
|
|
12
|
+
|
|
13
|
+
1. **Initialize a new project:**
|
|
14
|
+
```bash
|
|
15
|
+
mkdir my-first-skill
|
|
16
|
+
cd my-first-skill
|
|
17
|
+
lua init
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
2. **Create a simple tool:**
|
|
21
|
+
```typescript
|
|
22
|
+
// tools/HelloTool.ts
|
|
23
|
+
import { LuaTool } from "lua-cli/skill";
|
|
24
|
+
import { z } from "zod";
|
|
25
|
+
|
|
26
|
+
export default class HelloTool implements LuaTool<z.ZodObject<any>, z.ZodObject<any>> {
|
|
27
|
+
name = "hello";
|
|
28
|
+
description = "Say hello to someone";
|
|
29
|
+
|
|
30
|
+
inputSchema = z.object({
|
|
31
|
+
name: z.string().describe("Name to greet")
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
outputSchema = z.object({
|
|
35
|
+
message: z.string(),
|
|
36
|
+
timestamp: z.string()
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
async execute(input) {
|
|
40
|
+
return {
|
|
41
|
+
message: `Hello, ${input.name}!`,
|
|
42
|
+
timestamp: new Date().toISOString()
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
3. **Register the tool:**
|
|
49
|
+
```typescript
|
|
50
|
+
// index.ts
|
|
51
|
+
import { LuaSkill } from "lua-cli/skill";
|
|
52
|
+
import HelloTool from "./tools/HelloTool";
|
|
53
|
+
|
|
54
|
+
const skill = new LuaSkill();
|
|
55
|
+
skill.addTool(new HelloTool());
|
|
56
|
+
|
|
57
|
+
// Test the tool
|
|
58
|
+
async function test() {
|
|
59
|
+
const result = await skill.run({
|
|
60
|
+
tool: "hello",
|
|
61
|
+
name: "World"
|
|
62
|
+
});
|
|
63
|
+
console.log(result);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
test().catch(console.error);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
4. **Compile and test:**
|
|
70
|
+
```bash
|
|
71
|
+
lua compile
|
|
72
|
+
lua test
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## ๐ฏ Common Patterns
|
|
76
|
+
|
|
77
|
+
### API Call Tool
|
|
78
|
+
```typescript
|
|
79
|
+
import axios from "axios";
|
|
80
|
+
|
|
81
|
+
export default class WeatherTool implements LuaTool<z.ZodObject<any>, z.ZodObject<any>> {
|
|
82
|
+
name = "weather";
|
|
83
|
+
description = "Get weather for a city";
|
|
84
|
+
|
|
85
|
+
inputSchema = z.object({
|
|
86
|
+
city: z.string().describe("City name")
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
outputSchema = z.object({
|
|
90
|
+
temperature: z.number(),
|
|
91
|
+
condition: z.string(),
|
|
92
|
+
city: z.string()
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
async execute(input) {
|
|
96
|
+
const response = await axios.get(`https://api.weather.com/v1/current`, {
|
|
97
|
+
params: { q: input.city }
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
temperature: response.data.temp_c,
|
|
102
|
+
condition: response.data.condition.text,
|
|
103
|
+
city: input.city
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Data Processing Tool
|
|
110
|
+
```typescript
|
|
111
|
+
export default class ProcessDataTool implements LuaTool<z.ZodObject<any>, z.ZodObject<any>> {
|
|
112
|
+
name = "process_data";
|
|
113
|
+
description = "Process and transform data";
|
|
114
|
+
|
|
115
|
+
inputSchema = z.object({
|
|
116
|
+
data: z.array(z.any()).describe("Array of data to process"),
|
|
117
|
+
operation: z.enum(["sort", "filter", "map"]).describe("Operation to perform")
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
outputSchema = z.object({
|
|
121
|
+
result: z.array(z.any()),
|
|
122
|
+
count: z.number()
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
async execute(input) {
|
|
126
|
+
let result;
|
|
127
|
+
|
|
128
|
+
switch (input.operation) {
|
|
129
|
+
case "sort":
|
|
130
|
+
result = input.data.sort();
|
|
131
|
+
break;
|
|
132
|
+
case "filter":
|
|
133
|
+
result = input.data.filter(item => item > 0);
|
|
134
|
+
break;
|
|
135
|
+
case "map":
|
|
136
|
+
result = input.data.map(item => item * 2);
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
result,
|
|
142
|
+
count: result.length
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## ๐ง Next Steps
|
|
149
|
+
|
|
150
|
+
1. **Read the full documentation:**
|
|
151
|
+
- [README.md](./README.md) - Complete guide
|
|
152
|
+
- [DEVELOPER.md](./DEVELOPER.md) - Technical details
|
|
153
|
+
- [API.md](./API.md) - API reference
|
|
154
|
+
|
|
155
|
+
2. **Explore examples:**
|
|
156
|
+
- Check the `tools/` directory for working examples
|
|
157
|
+
- Look at `services/` for reusable components
|
|
158
|
+
|
|
159
|
+
3. **Build something awesome:**
|
|
160
|
+
- Create tools for your specific use case
|
|
161
|
+
- Integrate with your favorite APIs
|
|
162
|
+
- Share your skills with the community
|
|
163
|
+
|
|
164
|
+
## ๐ Need Help?
|
|
165
|
+
|
|
166
|
+
- Check the [troubleshooting section](./README.md#troubleshooting)
|
|
167
|
+
- Look at the [API reference](./API.md)
|
|
168
|
+
- Review the [developer documentation](./DEVELOPER.md)
|
|
169
|
+
|
|
170
|
+
Happy coding! ๐
|
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
# LuaSkill Template
|
|
2
|
+
|
|
3
|
+
This template provides a skeleton implementation demonstrating how to build LuaSkills with custom tools using the Lua CLI framework.
|
|
4
|
+
|
|
5
|
+
## ๐ Quick Start
|
|
6
|
+
|
|
7
|
+
1. **Install the Lua CLI globally:**
|
|
8
|
+
```bash
|
|
9
|
+
npm install -g lua-cli
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
2. **Initialize a new LuaSkill project:**
|
|
13
|
+
```bash
|
|
14
|
+
mkdir my-lua-skill
|
|
15
|
+
cd my-lua-skill
|
|
16
|
+
lua init
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
3. **Compile your skill:**
|
|
20
|
+
```bash
|
|
21
|
+
lua compile
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
4. **Test your tools:**
|
|
25
|
+
```bash
|
|
26
|
+
lua test
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## ๐ Project Structure
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
my-lua-skill/
|
|
33
|
+
โโโ tools/ # Your custom tools
|
|
34
|
+
โ โโโ GetWeatherTool.ts
|
|
35
|
+
โ โโโ GetUserDataTool.ts
|
|
36
|
+
โ โโโ CreatePostTool.ts
|
|
37
|
+
โโโ services/ # Shared services
|
|
38
|
+
โ โโโ ApiService.ts
|
|
39
|
+
โ โโโ GetWeather.ts
|
|
40
|
+
โโโ index.ts # Main skill definition
|
|
41
|
+
โโโ package.json # Dependencies
|
|
42
|
+
โโโ .lua/ # Generated files (auto-created)
|
|
43
|
+
โโโ deploy.json # Compiled skill data
|
|
44
|
+
โโโ *.js # Bundled tool files
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## ๐ ๏ธ Creating Tools
|
|
48
|
+
|
|
49
|
+
### Basic Tool Structure
|
|
50
|
+
|
|
51
|
+
Every tool must implement the `LuaTool` interface:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { LuaTool } from "lua-cli/skill";
|
|
55
|
+
import { z } from "zod";
|
|
56
|
+
|
|
57
|
+
export default class MyTool implements LuaTool<z.ZodObject<any>, z.ZodObject<any>> {
|
|
58
|
+
name = "my_tool";
|
|
59
|
+
description = "Description of what this tool does";
|
|
60
|
+
|
|
61
|
+
inputSchema = z.object({
|
|
62
|
+
// Define your input parameters
|
|
63
|
+
param1: z.string().describe("Description of param1"),
|
|
64
|
+
param2: z.number().describe("Description of param2")
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
outputSchema = z.object({
|
|
68
|
+
// Define your output structure
|
|
69
|
+
result: z.string(),
|
|
70
|
+
success: z.boolean()
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
async execute(input: z.infer<typeof this.inputSchema>) {
|
|
74
|
+
// Your tool logic here
|
|
75
|
+
return {
|
|
76
|
+
result: "Tool executed successfully",
|
|
77
|
+
success: true
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Tool Examples
|
|
84
|
+
|
|
85
|
+
#### 1. Simple Data Processing Tool
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { LuaTool } from "lua-cli/skill";
|
|
89
|
+
import { z } from "zod";
|
|
90
|
+
|
|
91
|
+
export default class ProcessDataTool implements LuaTool<z.ZodObject<any>, z.ZodObject<any>> {
|
|
92
|
+
name = "process_data";
|
|
93
|
+
description = "Process and transform input data";
|
|
94
|
+
|
|
95
|
+
inputSchema = z.object({
|
|
96
|
+
data: z.string().describe("Raw data to process"),
|
|
97
|
+
format: z.enum(["json", "xml", "csv"]).describe("Output format")
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
outputSchema = z.object({
|
|
101
|
+
processedData: z.string(),
|
|
102
|
+
format: z.string(),
|
|
103
|
+
timestamp: z.string()
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
async execute(input) {
|
|
107
|
+
// Process the data based on format
|
|
108
|
+
let processedData;
|
|
109
|
+
switch (input.format) {
|
|
110
|
+
case "json":
|
|
111
|
+
processedData = JSON.stringify({ data: input.data });
|
|
112
|
+
break;
|
|
113
|
+
case "xml":
|
|
114
|
+
processedData = `<data>${input.data}</data>`;
|
|
115
|
+
break;
|
|
116
|
+
case "csv":
|
|
117
|
+
processedData = `data\n"${input.data}"`;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
processedData,
|
|
123
|
+
format: input.format,
|
|
124
|
+
timestamp: new Date().toISOString()
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### 2. HTTP API Tool
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { LuaTool } from "lua-cli/skill";
|
|
134
|
+
import { z } from "zod";
|
|
135
|
+
import axios from "axios";
|
|
136
|
+
|
|
137
|
+
export default class ApiCallTool implements LuaTool<z.ZodObject<any>, z.ZodObject<any>> {
|
|
138
|
+
name = "api_call";
|
|
139
|
+
description = "Make HTTP API calls";
|
|
140
|
+
|
|
141
|
+
inputSchema = z.object({
|
|
142
|
+
url: z.string().url().describe("API endpoint URL"),
|
|
143
|
+
method: z.enum(["GET", "POST", "PUT", "DELETE"]).describe("HTTP method"),
|
|
144
|
+
data: z.any().optional().describe("Request body data"),
|
|
145
|
+
headers: z.record(z.string()).optional().describe("Custom headers")
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
outputSchema = z.object({
|
|
149
|
+
status: z.number(),
|
|
150
|
+
data: z.any(),
|
|
151
|
+
success: z.boolean(),
|
|
152
|
+
error: z.string().optional()
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
async execute(input) {
|
|
156
|
+
try {
|
|
157
|
+
const response = await axios({
|
|
158
|
+
url: input.url,
|
|
159
|
+
method: input.method,
|
|
160
|
+
data: input.data,
|
|
161
|
+
headers: input.headers || {}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
status: response.status,
|
|
166
|
+
data: response.data,
|
|
167
|
+
success: true
|
|
168
|
+
};
|
|
169
|
+
} catch (error: any) {
|
|
170
|
+
return {
|
|
171
|
+
status: error.response?.status || 0,
|
|
172
|
+
data: null,
|
|
173
|
+
success: false,
|
|
174
|
+
error: error.message
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
#### 3. File Operations Tool
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
import { LuaTool } from "lua-cli/skill";
|
|
185
|
+
import { z } from "zod";
|
|
186
|
+
import fs from "fs/promises";
|
|
187
|
+
import path from "path";
|
|
188
|
+
|
|
189
|
+
export default class FileTool implements LuaTool<z.ZodObject<any>, z.ZodObject<any>> {
|
|
190
|
+
name = "file_operations";
|
|
191
|
+
description = "Perform file system operations";
|
|
192
|
+
|
|
193
|
+
inputSchema = z.object({
|
|
194
|
+
operation: z.enum(["read", "write", "list", "delete"]).describe("File operation to perform"),
|
|
195
|
+
path: z.string().describe("File or directory path"),
|
|
196
|
+
content: z.string().optional().describe("Content to write (for write operations)")
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
outputSchema = z.object({
|
|
200
|
+
success: z.boolean(),
|
|
201
|
+
data: z.any().optional(),
|
|
202
|
+
error: z.string().optional()
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
async execute(input) {
|
|
206
|
+
try {
|
|
207
|
+
switch (input.operation) {
|
|
208
|
+
case "read":
|
|
209
|
+
const content = await fs.readFile(input.path, "utf8");
|
|
210
|
+
return { success: true, data: content };
|
|
211
|
+
|
|
212
|
+
case "write":
|
|
213
|
+
await fs.writeFile(input.path, input.content || "");
|
|
214
|
+
return { success: true, data: "File written successfully" };
|
|
215
|
+
|
|
216
|
+
case "list":
|
|
217
|
+
const files = await fs.readdir(input.path);
|
|
218
|
+
return { success: true, data: files };
|
|
219
|
+
|
|
220
|
+
case "delete":
|
|
221
|
+
await fs.unlink(input.path);
|
|
222
|
+
return { success: true, data: "File deleted successfully" };
|
|
223
|
+
|
|
224
|
+
default:
|
|
225
|
+
return { success: false, error: "Invalid operation" };
|
|
226
|
+
}
|
|
227
|
+
} catch (error: any) {
|
|
228
|
+
return { success: false, error: error.message };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## ๐ง Creating Services
|
|
235
|
+
|
|
236
|
+
Services provide reusable functionality across multiple tools:
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
// services/DatabaseService.ts
|
|
240
|
+
import axios from "axios";
|
|
241
|
+
|
|
242
|
+
export default class DatabaseService {
|
|
243
|
+
private baseUrl: string;
|
|
244
|
+
|
|
245
|
+
constructor(baseUrl: string) {
|
|
246
|
+
this.baseUrl = baseUrl;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async query(sql: string) {
|
|
250
|
+
const response = await axios.post(`${this.baseUrl}/query`, { sql });
|
|
251
|
+
return response.data;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async insert(table: string, data: any) {
|
|
255
|
+
const response = await axios.post(`${this.baseUrl}/insert`, { table, data });
|
|
256
|
+
return response.data;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## ๐ Main Skill Definition
|
|
262
|
+
|
|
263
|
+
Your `index.ts` file defines the skill and registers tools:
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
import { LuaSkill } from "lua-cli/skill";
|
|
267
|
+
import ProcessDataTool from "./tools/ProcessDataTool";
|
|
268
|
+
import ApiCallTool from "./tools/ApiCallTool";
|
|
269
|
+
import FileTool from "./tools/FileTool";
|
|
270
|
+
|
|
271
|
+
// Initialize skill
|
|
272
|
+
const skill = new LuaSkill();
|
|
273
|
+
|
|
274
|
+
// Add tools
|
|
275
|
+
skill.addTool(new ProcessDataTool());
|
|
276
|
+
skill.addTool(new ApiCallTool());
|
|
277
|
+
skill.addTool(new FileTool());
|
|
278
|
+
|
|
279
|
+
// Test cases (optional)
|
|
280
|
+
const testCases = [
|
|
281
|
+
{ tool: "process_data", data: "Hello World", format: "json" },
|
|
282
|
+
{ tool: "api_call", url: "https://httpbin.org/get", method: "GET" },
|
|
283
|
+
{ tool: "file_operations", operation: "list", path: "./" }
|
|
284
|
+
];
|
|
285
|
+
|
|
286
|
+
async function runTests() {
|
|
287
|
+
console.log("๐งช Running tool tests...\n");
|
|
288
|
+
|
|
289
|
+
for (const [index, testCase] of testCases.entries()) {
|
|
290
|
+
try {
|
|
291
|
+
console.log(`Test ${index + 1}: ${testCase.tool}`);
|
|
292
|
+
const result = await skill.run(testCase);
|
|
293
|
+
console.log("โ
Success:", result);
|
|
294
|
+
} catch (error: any) {
|
|
295
|
+
console.log("โ Error:", error.message);
|
|
296
|
+
}
|
|
297
|
+
console.log("");
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Run tests if this file is executed directly
|
|
302
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
303
|
+
runTests().catch(console.error);
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## ๐ฏ Best Practices
|
|
308
|
+
|
|
309
|
+
### 1. Input Validation
|
|
310
|
+
Always use Zod schemas for robust input validation:
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
inputSchema = z.object({
|
|
314
|
+
email: z.string().email().describe("Valid email address"),
|
|
315
|
+
age: z.number().min(0).max(120).describe("Age between 0 and 120"),
|
|
316
|
+
tags: z.array(z.string()).optional().describe("Optional array of tags")
|
|
317
|
+
});
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### 2. Error Handling
|
|
321
|
+
Provide meaningful error messages:
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
async execute(input) {
|
|
325
|
+
try {
|
|
326
|
+
// Your logic here
|
|
327
|
+
return { success: true, data: result };
|
|
328
|
+
} catch (error: any) {
|
|
329
|
+
return {
|
|
330
|
+
success: false,
|
|
331
|
+
error: error.message,
|
|
332
|
+
timestamp: new Date().toISOString()
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### 3. Async Operations
|
|
339
|
+
Use async/await for better error handling:
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
async execute(input) {
|
|
343
|
+
const result = await someAsyncOperation(input);
|
|
344
|
+
return result;
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### 4. Service Reuse
|
|
349
|
+
Extract common functionality into services:
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
// In your tool
|
|
353
|
+
import DatabaseService from "../services/DatabaseService";
|
|
354
|
+
|
|
355
|
+
export default class UserTool {
|
|
356
|
+
private dbService = new DatabaseService("http://localhost:3000");
|
|
357
|
+
|
|
358
|
+
async execute(input) {
|
|
359
|
+
const users = await this.dbService.query("SELECT * FROM users");
|
|
360
|
+
return { users };
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
## ๐ฆ Dependencies
|
|
366
|
+
|
|
367
|
+
Add external dependencies to your `package.json`:
|
|
368
|
+
|
|
369
|
+
```json
|
|
370
|
+
{
|
|
371
|
+
"dependencies": {
|
|
372
|
+
"axios": "^1.6.0",
|
|
373
|
+
"zod": "^3.22.0"
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
The Lua CLI will automatically bundle these dependencies when you run `lua compile`.
|
|
379
|
+
|
|
380
|
+
## ๐งช Testing
|
|
381
|
+
|
|
382
|
+
### Interactive Testing
|
|
383
|
+
```bash
|
|
384
|
+
lua test
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Programmatic Testing
|
|
388
|
+
```typescript
|
|
389
|
+
const result = await skill.run({
|
|
390
|
+
tool: "my_tool",
|
|
391
|
+
param1: "value1",
|
|
392
|
+
param2: 42
|
|
393
|
+
});
|
|
394
|
+
console.log(result);
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
## ๐ Deployment
|
|
398
|
+
|
|
399
|
+
Once your skill is ready:
|
|
400
|
+
|
|
401
|
+
1. **Compile:**
|
|
402
|
+
```bash
|
|
403
|
+
lua compile
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
2. **Deploy:**
|
|
407
|
+
```bash
|
|
408
|
+
lua deploy
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
The compiled skill data will be in `.lua/deploy.json` and can be used with the Lua platform.
|
|
412
|
+
|
|
413
|
+
## ๐ API Reference
|
|
414
|
+
|
|
415
|
+
### LuaSkill Class
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
class LuaSkill {
|
|
419
|
+
constructor()
|
|
420
|
+
addTool<TInput, TOutput>(tool: LuaTool<TInput, TOutput>): void
|
|
421
|
+
async run(input: Record<string, any>): Promise<any>
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### LuaTool Interface
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
interface LuaTool<TInput extends ZodType, TOutput extends ZodType> {
|
|
429
|
+
name: string;
|
|
430
|
+
description: string;
|
|
431
|
+
inputSchema: TInput;
|
|
432
|
+
outputSchema: TOutput;
|
|
433
|
+
execute(input: z.infer<TInput>): Promise<z.infer<TOutput>>;
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
## ๐ Troubleshooting
|
|
438
|
+
|
|
439
|
+
### Common Issues
|
|
440
|
+
|
|
441
|
+
1. **"Tool not found" error:**
|
|
442
|
+
- Ensure the tool name matches exactly
|
|
443
|
+
- Check that the tool is added to the skill
|
|
444
|
+
|
|
445
|
+
2. **Input validation errors:**
|
|
446
|
+
- Verify your Zod schema matches the input structure
|
|
447
|
+
- Check required vs optional fields
|
|
448
|
+
|
|
449
|
+
3. **Bundling errors:**
|
|
450
|
+
- Ensure all dependencies are in `package.json`
|
|
451
|
+
- Check import paths are correct
|
|
452
|
+
|
|
453
|
+
4. **Runtime errors:**
|
|
454
|
+
- Use try/catch blocks in your execute methods
|
|
455
|
+
- Check that all required globals are available
|
|
456
|
+
|
|
457
|
+
### Debug Tips
|
|
458
|
+
|
|
459
|
+
- Use `console.log` for debugging (output appears in test mode)
|
|
460
|
+
- Test individual tools before adding to the skill
|
|
461
|
+
- Validate schemas with Zod's `.parse()` method
|
|
462
|
+
- Check the generated `.lua/deploy.json` for compilation issues
|
|
463
|
+
|
|
464
|
+
## ๐ Examples
|
|
465
|
+
|
|
466
|
+
See the `tools/` directory for complete working examples:
|
|
467
|
+
- `GetWeatherTool.ts` - Simple API call
|
|
468
|
+
- `GetUserDataTool.ts` - Complex service integration
|
|
469
|
+
- `CreatePostTool.ts` - POST request with data
|
|
470
|
+
|
|
471
|
+
## ๐ค Contributing
|
|
472
|
+
|
|
473
|
+
Found a bug or want to add a feature? Check out our [contributing guidelines](../../CONTRIBUTING.md).
|
|
474
|
+
|
|
475
|
+
## ๐ License
|
|
476
|
+
|
|
477
|
+
This template is part of the Lua CLI framework. See the main [LICENSE](../../LICENSE) file for details.
|
package/template/index.ts
CHANGED
|
@@ -1,29 +1,53 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { LuaSkill, LuaTool } from "lua-cli/skill";
|
|
1
|
+
import { LuaSkill } from "lua-cli/skill";
|
|
3
2
|
import GetWeatherTool from "./tools/GetWeatherTool";
|
|
4
3
|
import GetUserDataTool from "./tools/GetUserDataTool";
|
|
5
4
|
import CreatePostTool from "./tools/CreatePostTool";
|
|
5
|
+
import CalculatorTool from "./tools/CalculatorTool";
|
|
6
|
+
import AdvancedMathTool from "./tools/AdvancedMathTool";
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
// Initialize skill with tools
|
|
9
|
+
const skill = new LuaSkill();
|
|
8
10
|
skill.addTool(new GetWeatherTool());
|
|
9
11
|
skill.addTool(new GetUserDataTool());
|
|
10
12
|
skill.addTool(new CreatePostTool());
|
|
13
|
+
skill.addTool(new CalculatorTool());
|
|
14
|
+
skill.addTool(new AdvancedMathTool());
|
|
15
|
+
|
|
16
|
+
// Test cases
|
|
17
|
+
const testCases = [
|
|
18
|
+
{ tool: "get_weather", city: "London" },
|
|
19
|
+
{ tool: "get_user_data", userId: "user123" },
|
|
20
|
+
{ tool: "create_post", title: "Test Post", content: "This is a test post content" },
|
|
21
|
+
{ tool: "calculator", operation: "add", a: 5, b: 3 },
|
|
22
|
+
{ tool: "advanced_math", operation: "factorial", numbers: [5] },
|
|
23
|
+
{ tool: "advanced_math", operation: "is_prime", numbers: [17] },
|
|
24
|
+
{ tool: "advanced_math", operation: "fibonacci", numbers: [10] },
|
|
25
|
+
{ tool: "advanced_math", operation: "gcd", numbers: [48, 18] },
|
|
26
|
+
// This should fail - wrong property name
|
|
27
|
+
{ tool: "get_weather", cityLong: "London", apiKey: "123" }
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
async function runTests() {
|
|
31
|
+
console.log("๐งช Running tool tests...\n");
|
|
32
|
+
|
|
33
|
+
for (const [index, testCase] of testCases.entries()) {
|
|
34
|
+
try {
|
|
35
|
+
console.log(`Test ${index + 1}: ${testCase.tool}`);
|
|
36
|
+
const result = await skill.run(testCase);
|
|
37
|
+
console.log("โ
Success:", result);
|
|
38
|
+
} catch (error: any) {
|
|
39
|
+
console.log("โ Error:", error.message);
|
|
40
|
+
}
|
|
41
|
+
console.log(""); // Empty line for readability
|
|
42
|
+
}
|
|
43
|
+
}
|
|
11
44
|
|
|
12
45
|
async function main() {
|
|
13
46
|
try {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
console.log("User data tool:", await skill.run({ tool: "get_user_data", userId: "user123" }));
|
|
19
|
-
|
|
20
|
-
// Test post creation tool with axios
|
|
21
|
-
console.log("Post creation tool:", await skill.run({ tool: "create_post", title: "Test Post", content: "This is a test post content" }));
|
|
22
|
-
|
|
23
|
-
// This should fail - wrong property name
|
|
24
|
-
console.log("Invalid input:", await skill.run({ tool: "get_weather", cityLong: "London", apiKey: "123" }));
|
|
25
|
-
} catch (error: any) {
|
|
26
|
-
console.error("Validation error:", error.message);
|
|
47
|
+
await runTests();
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error("๐ฅ Unexpected error:", error);
|
|
50
|
+
process.exit(1);
|
|
27
51
|
}
|
|
28
52
|
}
|
|
29
53
|
|