lua-cli 2.2.8-alpha.1 → 2.3.0-alpha.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/API_REFERENCE.md +1408 -0
- package/CLI_REFERENCE.md +818 -0
- package/GETTING_STARTED.md +1040 -0
- package/README.md +738 -424
- package/TEMPLATE_GUIDE.md +1398 -0
- package/dist/api/agent.api.service.d.ts +45 -0
- package/dist/api/agent.api.service.js +57 -0
- package/dist/api/auth.api.service.d.ts +48 -0
- package/dist/api/auth.api.service.js +54 -0
- package/dist/api/basket.api.service.d.ts +85 -0
- package/dist/api/basket.api.service.js +164 -0
- package/dist/api/chat.api.service.d.ts +21 -0
- package/dist/api/chat.api.service.js +24 -0
- package/dist/api/credentials.d.ts +24 -0
- package/dist/api/credentials.js +46 -0
- package/dist/api/custom.data.api.service.d.ts +69 -0
- package/dist/api/custom.data.api.service.js +125 -0
- package/dist/api/lazy-instances.d.ts +49 -0
- package/dist/api/lazy-instances.js +95 -0
- package/dist/api/order.api.service.d.ts +53 -0
- package/dist/api/order.api.service.js +95 -0
- package/dist/api/products.api.service.d.ts +66 -0
- package/dist/api/products.api.service.js +112 -0
- package/dist/api/skills.api.service.d.ts +77 -0
- package/dist/api/skills.api.service.js +88 -0
- package/dist/api/tool.api.service.d.ts +52 -0
- package/dist/api/tool.api.service.js +73 -0
- package/dist/api/user.data.api.service.d.ts +33 -0
- package/dist/api/user.data.api.service.js +59 -0
- package/dist/api-exports.d.ts +271 -0
- package/dist/api-exports.js +372 -0
- package/dist/cli/command-definitions.d.ts +30 -0
- package/dist/cli/command-definitions.js +71 -0
- package/dist/commands/agents.d.ts +20 -0
- package/dist/commands/agents.js +24 -2
- package/dist/commands/apiKey.d.ts +23 -0
- package/dist/commands/apiKey.js +23 -0
- package/dist/commands/compile.d.ts +24 -0
- package/dist/commands/compile.js +67 -759
- package/dist/commands/configure.d.ts +24 -0
- package/dist/commands/configure.js +31 -96
- package/dist/commands/deploy.d.ts +31 -19
- package/dist/commands/deploy.js +45 -74
- package/dist/commands/destroy.d.ts +27 -0
- package/dist/commands/destroy.js +27 -1
- package/dist/commands/dev.d.ts +25 -62
- package/dist/commands/dev.js +58 -873
- package/dist/commands/init.d.ts +27 -0
- package/dist/commands/init.js +98 -260
- package/dist/commands/push.d.ts +24 -21
- package/dist/commands/push.js +39 -92
- package/dist/commands/test.d.ts +26 -0
- package/dist/commands/test.js +41 -188
- package/dist/common/basket.instance.d.ts +78 -0
- package/dist/common/basket.instance.js +132 -0
- package/dist/common/data.entry.instance.d.ts +39 -0
- package/dist/common/data.entry.instance.js +76 -0
- package/dist/common/http.client.d.ts +64 -0
- package/dist/common/http.client.js +133 -0
- package/dist/common/order.instance.d.ts +40 -0
- package/dist/common/order.instance.js +79 -0
- package/dist/common/product.instance.d.ts +33 -0
- package/dist/common/product.instance.js +63 -0
- package/dist/common/product.pagination.instance.d.ts +43 -0
- package/dist/common/product.pagination.instance.js +74 -0
- package/dist/common/product.search.instance.d.ts +22 -0
- package/dist/common/product.search.instance.js +40 -0
- package/dist/common/user.instance.d.ts +41 -0
- package/dist/common/user.instance.js +84 -0
- package/dist/config/auth.constants.d.ts +11 -0
- package/dist/config/auth.constants.js +11 -0
- package/dist/config/compile.constants.d.ts +67 -0
- package/dist/config/compile.constants.js +99 -0
- package/dist/config/constants.d.ts +5 -0
- package/dist/config/constants.js +5 -0
- package/dist/config/dev.constants.d.ts +65 -0
- package/dist/config/dev.constants.js +79 -0
- package/dist/config/init.constants.d.ts +23 -0
- package/dist/config/init.constants.js +41 -0
- package/dist/index.d.ts +19 -3
- package/dist/index.js +28 -44
- package/dist/interfaces/admin.d.ts +101 -0
- package/dist/interfaces/admin.js +5 -0
- package/dist/interfaces/agent.d.ts +107 -0
- package/dist/interfaces/agent.js +5 -0
- package/dist/interfaces/baskets.d.ts +135 -0
- package/dist/interfaces/baskets.js +19 -0
- package/dist/interfaces/chat.d.ts +61 -0
- package/dist/interfaces/chat.js +5 -0
- package/dist/interfaces/common.d.ts +62 -0
- package/dist/interfaces/common.js +8 -0
- package/dist/interfaces/compile.d.ts +11 -0
- package/dist/interfaces/compile.js +4 -0
- package/dist/interfaces/custom.data.d.ts +82 -0
- package/dist/interfaces/custom.data.js +5 -0
- package/dist/interfaces/deploy.d.ts +29 -0
- package/dist/interfaces/deploy.js +4 -0
- package/dist/interfaces/dev.d.ts +53 -0
- package/dist/interfaces/dev.js +5 -0
- package/dist/interfaces/init.d.ts +60 -0
- package/dist/interfaces/init.js +4 -0
- package/dist/interfaces/orders.d.ts +91 -0
- package/dist/interfaces/orders.js +19 -0
- package/dist/interfaces/product.d.ts +65 -0
- package/dist/interfaces/product.js +5 -0
- package/dist/interfaces/push.d.ts +26 -0
- package/dist/interfaces/push.js +4 -0
- package/dist/interfaces/test.d.ts +36 -0
- package/dist/interfaces/test.js +4 -0
- package/dist/services/auth.d.ts +54 -99
- package/dist/services/auth.js +76 -12
- package/dist/types/api-contracts.d.ts +211 -0
- package/dist/types/api-contracts.js +8 -0
- package/dist/types/compile.types.d.ts +76 -0
- package/dist/types/compile.types.js +4 -0
- package/dist/types/index.d.ts +23 -85
- package/dist/types/index.js +25 -14
- package/dist/types/skill.d.ts +142 -0
- package/dist/{skill.js → types/skill.js} +66 -19
- package/dist/types/tool-validation.d.ts +34 -0
- package/dist/types/tool-validation.js +42 -0
- package/dist/utils/auth-flows.d.ts +26 -0
- package/dist/utils/auth-flows.js +141 -0
- package/dist/utils/bundling.d.ts +36 -0
- package/dist/utils/bundling.js +137 -0
- package/dist/utils/compile.d.ts +37 -0
- package/dist/utils/compile.js +242 -0
- package/dist/utils/deploy-api.d.ts +26 -0
- package/dist/utils/deploy-api.js +53 -0
- package/dist/utils/deploy-helpers.d.ts +46 -0
- package/dist/utils/deploy-helpers.js +86 -0
- package/dist/utils/deployment.d.ts +25 -0
- package/dist/utils/deployment.js +161 -0
- package/dist/utils/dev-api.d.ts +61 -0
- package/dist/utils/dev-api.js +262 -0
- package/dist/utils/dev-helpers.d.ts +46 -0
- package/dist/utils/dev-helpers.js +83 -0
- package/dist/utils/dev-server.d.ts +24 -0
- package/dist/utils/dev-server.js +555 -0
- package/dist/utils/dev-watcher.d.ts +31 -0
- package/dist/utils/dev-watcher.js +110 -0
- package/dist/utils/files.js +0 -5
- package/dist/utils/init-agent.d.ts +34 -0
- package/dist/utils/init-agent.js +129 -0
- package/dist/utils/init-helpers.d.ts +41 -0
- package/dist/utils/init-helpers.js +73 -0
- package/dist/utils/init-prompts.d.ts +47 -0
- package/dist/utils/init-prompts.js +168 -0
- package/dist/utils/push-api.d.ts +15 -0
- package/dist/utils/push-api.js +48 -0
- package/dist/utils/push-helpers.d.ts +38 -0
- package/dist/utils/push-helpers.js +84 -0
- package/dist/utils/sandbox-storage.d.ts +27 -0
- package/dist/utils/sandbox-storage.js +71 -0
- package/dist/utils/sandbox.js +78 -118
- package/dist/utils/skill-management.d.ts +14 -0
- package/dist/utils/skill-management.js +148 -0
- package/dist/utils/test-helpers.d.ts +40 -0
- package/dist/utils/test-helpers.js +92 -0
- package/dist/utils/test-prompts.d.ts +23 -0
- package/dist/utils/test-prompts.js +186 -0
- package/dist/utils/tool-detection.d.ts +18 -0
- package/dist/utils/tool-detection.js +110 -0
- package/dist/web/app.css +14 -9
- package/package.json +11 -12
- package/template/QUICKSTART.md +299 -144
- package/template/README.md +928 -349
- package/template/TOOL_EXAMPLES.md +655 -0
- package/template/package-lock.json +3781 -0
- package/template/package.json +1 -1
- package/template/src/index.ts +81 -40
- package/template/src/tools/BasketTool.ts +128 -0
- package/template/src/tools/CustomDataTool.ts +7 -13
- package/template/src/tools/OrderTool.ts +54 -0
- package/template/src/tools/PaymentTool.ts +1 -1
- package/template/src/tools/ProductsTool.ts +56 -118
- package/template/src/tools/UserDataTool.ts +4 -27
- package/dist/custom-data-api.d.ts +0 -72
- package/dist/custom-data-api.js +0 -174
- package/dist/product-api.d.ts +0 -197
- package/dist/product-api.js +0 -152
- package/dist/services/api.d.ts +0 -569
- package/dist/services/api.js +0 -625
- package/dist/skill.d.ts +0 -50
- package/dist/types.d.ts +0 -1
- package/dist/types.js +0 -2
- package/dist/user-data-api.d.ts +0 -39
- package/dist/user-data-api.js +0 -50
- package/template/API.md +0 -604
- package/template/DEVELOPER.md +0 -771
- package/template/lua.skill.yaml +0 -16
package/API_REFERENCE.md
ADDED
|
@@ -0,0 +1,1408 @@
|
|
|
1
|
+
# Lua CLI - API Reference
|
|
2
|
+
|
|
3
|
+
Complete API reference for building Lua AI skills.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 📋 Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Core Concepts](#core-concepts)
|
|
11
|
+
- [LuaSkill Class](#luaskill-class)
|
|
12
|
+
- [LuaTool Interface](#luatool-interface)
|
|
13
|
+
- [Platform APIs](#platform-apis)
|
|
14
|
+
- [Environment Variables](#environment-variables)
|
|
15
|
+
- [Complete Examples](#complete-examples)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install lua-cli zod
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Dependencies:**
|
|
26
|
+
- `lua-cli` - Lua CLI and APIs
|
|
27
|
+
- `zod` - Schema validation (peer dependency)
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Core Concepts
|
|
32
|
+
|
|
33
|
+
### What is a Lua Skill?
|
|
34
|
+
|
|
35
|
+
A **skill** is a collection of **tools** that an AI agent can use. Each tool:
|
|
36
|
+
- Has a specific purpose (e.g., "get weather", "create order")
|
|
37
|
+
- Accepts validated inputs (using Zod schemas)
|
|
38
|
+
- Returns structured outputs
|
|
39
|
+
- Can call external APIs, databases, or services
|
|
40
|
+
|
|
41
|
+
### Architecture
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
LuaSkill
|
|
45
|
+
├── Tool 1 (e.g., Get Weather)
|
|
46
|
+
├── Tool 2 (e.g., Create Product)
|
|
47
|
+
└── Tool 3 (e.g., Send Email)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The AI agent:
|
|
51
|
+
1. Receives user request
|
|
52
|
+
2. Selects appropriate tool(s)
|
|
53
|
+
3. Calls tools with validated inputs
|
|
54
|
+
4. Returns results to user
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## LuaSkill Class
|
|
59
|
+
|
|
60
|
+
### Importing
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { LuaSkill } from 'lua-cli';
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Constructor
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
new LuaSkill(config: LuaSkillConfig)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Parameters:**
|
|
73
|
+
|
|
74
|
+
| Parameter | Type | Required | Description |
|
|
75
|
+
|-----------|------|----------|-------------|
|
|
76
|
+
| `config.name` | string | No | Skill name (default: 'unnamed-skill') |
|
|
77
|
+
| `config.version` | string | No | Skill version (default: '1.0.0') |
|
|
78
|
+
| `config.description` | string | Yes | Brief description (1-2 sentences) |
|
|
79
|
+
| `config.context` | string | Yes | Detailed usage instructions for the AI |
|
|
80
|
+
| `config.tools` | LuaTool[] | No | Array of tools to add immediately |
|
|
81
|
+
|
|
82
|
+
**Example:**
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
const skill = new LuaSkill({
|
|
86
|
+
name: 'weather-skill',
|
|
87
|
+
version: '1.0.0',
|
|
88
|
+
description: 'Provides weather information for any city',
|
|
89
|
+
context: 'Use the get_weather tool when users ask about weather, temperature, or conditions. The tool requires a city name and returns current weather data.',
|
|
90
|
+
tools: [new GetWeatherTool()]
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Methods
|
|
95
|
+
|
|
96
|
+
#### `addTool(tool: LuaTool): void`
|
|
97
|
+
|
|
98
|
+
Adds a single tool to the skill.
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
skill.addTool(new MyTool());
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Validation:**
|
|
105
|
+
- Tool name must be unique
|
|
106
|
+
- Tool name must only contain: `a-z`, `A-Z`, `0-9`, `-`, `_`
|
|
107
|
+
- Throws error if validation fails
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
#### `addTools(tools: LuaTool[]): void`
|
|
112
|
+
|
|
113
|
+
Adds multiple tools to the skill.
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
skill.addTools([
|
|
117
|
+
new Tool1(),
|
|
118
|
+
new Tool2(),
|
|
119
|
+
new Tool3()
|
|
120
|
+
]);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Validation:**
|
|
124
|
+
- All tools validated before adding
|
|
125
|
+
- Atomic operation (all or nothing)
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
### Best Practices
|
|
130
|
+
|
|
131
|
+
**✅ Good Context:**
|
|
132
|
+
```typescript
|
|
133
|
+
context: "Use get_weather for current conditions. Use search_products when users want to find items. Use create_order to complete purchases. Always confirm details before creating orders."
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**❌ Poor Context:**
|
|
137
|
+
```typescript
|
|
138
|
+
context: "A skill with tools"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Tips:**
|
|
142
|
+
- Be specific about when to use each tool
|
|
143
|
+
- Mention required vs optional parameters
|
|
144
|
+
- Include edge cases and limitations
|
|
145
|
+
- Give the AI clear decision criteria
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## LuaTool Interface
|
|
150
|
+
|
|
151
|
+
### Structure
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
interface LuaTool<TInput extends ZodType = ZodType> {
|
|
155
|
+
name: string;
|
|
156
|
+
description: string;
|
|
157
|
+
inputSchema: TInput;
|
|
158
|
+
execute: (input: any) => Promise<any>;
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Implementing a Tool
|
|
163
|
+
|
|
164
|
+
#### Method 1: Class Implementation
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
import { LuaTool } from 'lua-cli';
|
|
168
|
+
import { z } from 'zod';
|
|
169
|
+
|
|
170
|
+
export default class GetWeatherTool implements LuaTool {
|
|
171
|
+
name = "get_weather";
|
|
172
|
+
description = "Get current weather for a city";
|
|
173
|
+
|
|
174
|
+
inputSchema = z.object({
|
|
175
|
+
city: z.string().describe("City name"),
|
|
176
|
+
units: z.enum(['metric', 'imperial']).optional()
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
async execute(input: z.infer<typeof this.inputSchema>) {
|
|
180
|
+
// input is automatically validated and typed
|
|
181
|
+
const { city, units = 'metric' } = input;
|
|
182
|
+
|
|
183
|
+
// Call weather API...
|
|
184
|
+
const weather = await fetchWeather(city, units);
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
temperature: weather.temp,
|
|
188
|
+
condition: weather.condition,
|
|
189
|
+
city: weather.location
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
#### Method 2: Object Implementation
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
const weatherTool: LuaTool = {
|
|
199
|
+
name: "get_weather",
|
|
200
|
+
description: "Get current weather for a city",
|
|
201
|
+
inputSchema: z.object({
|
|
202
|
+
city: z.string()
|
|
203
|
+
}),
|
|
204
|
+
async execute(input) {
|
|
205
|
+
// Implementation...
|
|
206
|
+
return { temperature: 72 };
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Tool Properties
|
|
212
|
+
|
|
213
|
+
#### `name: string`
|
|
214
|
+
|
|
215
|
+
- **Format**: Lowercase, alphanumeric, hyphens, underscores only
|
|
216
|
+
- **Valid**: `get_weather`, `create-product`, `sendEmail123`
|
|
217
|
+
- **Invalid**: `get weather`, `create.product`, `send@email`
|
|
218
|
+
- **Purpose**: Unique identifier for the tool
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
#### `description: string`
|
|
223
|
+
|
|
224
|
+
- **Format**: Clear, concise description (1 sentence)
|
|
225
|
+
- **Purpose**: Helps AI understand when to use the tool
|
|
226
|
+
- **Best Practice**: Mention what the tool does and its primary use case
|
|
227
|
+
|
|
228
|
+
**Examples:**
|
|
229
|
+
```typescript
|
|
230
|
+
description = "Get current weather conditions for any city worldwide"
|
|
231
|
+
description = "Create a new product in the catalog with price and details"
|
|
232
|
+
description = "Search for products by name, category, or description"
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
#### `inputSchema: ZodType`
|
|
238
|
+
|
|
239
|
+
Zod schema defining valid inputs.
|
|
240
|
+
|
|
241
|
+
**Simple Schema:**
|
|
242
|
+
```typescript
|
|
243
|
+
inputSchema = z.object({
|
|
244
|
+
city: z.string()
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Complex Schema:**
|
|
249
|
+
```typescript
|
|
250
|
+
inputSchema = z.object({
|
|
251
|
+
city: z.string().describe("City name"),
|
|
252
|
+
units: z.enum(['metric', 'imperial']).default('metric'),
|
|
253
|
+
includeForecast: z.boolean().optional(),
|
|
254
|
+
days: z.number().min(1).max(7).optional()
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Nested Schema:**
|
|
259
|
+
```typescript
|
|
260
|
+
inputSchema = z.object({
|
|
261
|
+
user: z.object({
|
|
262
|
+
name: z.string(),
|
|
263
|
+
email: z.string().email()
|
|
264
|
+
}),
|
|
265
|
+
preferences: z.object({
|
|
266
|
+
notifications: z.boolean(),
|
|
267
|
+
language: z.string()
|
|
268
|
+
}).optional()
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**Supported Types:**
|
|
273
|
+
- `z.string()` - String values
|
|
274
|
+
- `z.number()` - Numeric values
|
|
275
|
+
- `z.boolean()` - True/false
|
|
276
|
+
- `z.enum([...])` - Fixed set of values
|
|
277
|
+
- `z.array(T)` - Arrays
|
|
278
|
+
- `z.object({...})` - Nested objects
|
|
279
|
+
- `.optional()` - Optional fields
|
|
280
|
+
- `.default(value)` - Default values
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
#### `execute: (input: any) => Promise<any>`
|
|
285
|
+
|
|
286
|
+
Async function that implements the tool logic.
|
|
287
|
+
|
|
288
|
+
**Signature:**
|
|
289
|
+
```typescript
|
|
290
|
+
async execute(input: z.infer<typeof this.inputSchema>) {
|
|
291
|
+
// Implementation
|
|
292
|
+
return result;
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Input:**
|
|
297
|
+
- Automatically validated against `inputSchema`
|
|
298
|
+
- Type-safe when using `z.infer<typeof this.inputSchema>`
|
|
299
|
+
|
|
300
|
+
**Return:**
|
|
301
|
+
- Can return any JSON-serializable value
|
|
302
|
+
- Should return structured data when possible
|
|
303
|
+
|
|
304
|
+
**Error Handling:**
|
|
305
|
+
```typescript
|
|
306
|
+
async execute(input: any) {
|
|
307
|
+
// Throw descriptive errors
|
|
308
|
+
if (!input.id) {
|
|
309
|
+
throw new Error("ID is required");
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
try {
|
|
313
|
+
const result = await externalApi.call(input);
|
|
314
|
+
return result;
|
|
315
|
+
} catch (error) {
|
|
316
|
+
// Re-throw with context
|
|
317
|
+
throw new Error(`Failed to call external API: ${error.message}`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## Platform APIs
|
|
325
|
+
|
|
326
|
+
The Lua CLI provides built-in APIs for common operations.
|
|
327
|
+
|
|
328
|
+
### Importing
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
import { User, Data, Products, Baskets, Orders } from 'lua-cli';
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## User API
|
|
337
|
+
|
|
338
|
+
Access and manage user data.
|
|
339
|
+
|
|
340
|
+
### `User.get()`
|
|
341
|
+
|
|
342
|
+
Retrieves the current user's data.
|
|
343
|
+
|
|
344
|
+
**Usage:**
|
|
345
|
+
```typescript
|
|
346
|
+
const user = await User.get();
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
**Returns:**
|
|
350
|
+
```typescript
|
|
351
|
+
{
|
|
352
|
+
id: string;
|
|
353
|
+
email: string;
|
|
354
|
+
name: string;
|
|
355
|
+
// ... additional user fields
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
**Example:**
|
|
360
|
+
```typescript
|
|
361
|
+
export class GetUserDataTool implements LuaTool {
|
|
362
|
+
name = "get_user_data";
|
|
363
|
+
description = "Retrieve current user's information";
|
|
364
|
+
inputSchema = z.object({});
|
|
365
|
+
|
|
366
|
+
async execute(input: any) {
|
|
367
|
+
const user = await User.get();
|
|
368
|
+
return {
|
|
369
|
+
name: user.name,
|
|
370
|
+
email: user.email
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## Data API
|
|
379
|
+
|
|
380
|
+
Store and retrieve custom data with vector search.
|
|
381
|
+
|
|
382
|
+
### `Data.create(collectionName, data, searchText?)`
|
|
383
|
+
|
|
384
|
+
Creates a new entry in a collection.
|
|
385
|
+
|
|
386
|
+
**Parameters:**
|
|
387
|
+
|
|
388
|
+
| Parameter | Type | Required | Description |
|
|
389
|
+
|-----------|------|----------|-------------|
|
|
390
|
+
| `collectionName` | string | Yes | Collection name (e.g., 'movies', 'customers') |
|
|
391
|
+
| `data` | object | Yes | Data to store (any JSON object) |
|
|
392
|
+
| `searchText` | string | No | Text for vector search indexing |
|
|
393
|
+
|
|
394
|
+
**Usage:**
|
|
395
|
+
```typescript
|
|
396
|
+
const entry = await Data.create('movies', {
|
|
397
|
+
title: 'Inception',
|
|
398
|
+
year: 2010,
|
|
399
|
+
director: 'Christopher Nolan'
|
|
400
|
+
}, 'Inception 2010 Christopher Nolan sci-fi thriller');
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Returns:**
|
|
404
|
+
```typescript
|
|
405
|
+
{
|
|
406
|
+
id: string;
|
|
407
|
+
data: object;
|
|
408
|
+
createdAt: number;
|
|
409
|
+
updatedAt: number;
|
|
410
|
+
searchText?: string;
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
### `Data.get(collectionName, filter?, page?, limit?)`
|
|
417
|
+
|
|
418
|
+
Retrieves entries from a collection.
|
|
419
|
+
|
|
420
|
+
**Parameters:**
|
|
421
|
+
|
|
422
|
+
| Parameter | Type | Default | Description |
|
|
423
|
+
|-----------|------|---------|-------------|
|
|
424
|
+
| `collectionName` | string | - | Collection name |
|
|
425
|
+
| `filter` | object | {} | Filter criteria |
|
|
426
|
+
| `page` | number | 1 | Page number |
|
|
427
|
+
| `limit` | number | 10 | Items per page |
|
|
428
|
+
|
|
429
|
+
**Usage:**
|
|
430
|
+
```typescript
|
|
431
|
+
// Get all
|
|
432
|
+
const movies = await Data.get('movies');
|
|
433
|
+
|
|
434
|
+
// With pagination
|
|
435
|
+
const page2 = await Data.get('movies', {}, 2, 20);
|
|
436
|
+
|
|
437
|
+
// With filter
|
|
438
|
+
const recentMovies = await Data.get('movies', { year: { $gte: 2020 } });
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
**Returns:**
|
|
442
|
+
```typescript
|
|
443
|
+
{
|
|
444
|
+
data: Entry[];
|
|
445
|
+
pagination: {
|
|
446
|
+
currentPage: number;
|
|
447
|
+
totalPages: number;
|
|
448
|
+
totalCount: number;
|
|
449
|
+
// ...
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
### `Data.getEntry(collectionName, entryId)`
|
|
457
|
+
|
|
458
|
+
Retrieves a specific entry by ID.
|
|
459
|
+
|
|
460
|
+
**Usage:**
|
|
461
|
+
```typescript
|
|
462
|
+
const movie = await Data.getEntry('movies', 'entry_abc123');
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
---
|
|
466
|
+
|
|
467
|
+
### `Data.update(collectionName, entryId, data)`
|
|
468
|
+
|
|
469
|
+
Updates an existing entry.
|
|
470
|
+
|
|
471
|
+
**Usage:**
|
|
472
|
+
```typescript
|
|
473
|
+
const updated = await Data.update('movies', 'entry_abc123', {
|
|
474
|
+
rating: 9.5,
|
|
475
|
+
reviews: 1000
|
|
476
|
+
});
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
### `Data.search(collectionName, searchText, limit?, scoreThreshold?)`
|
|
482
|
+
|
|
483
|
+
Performs vector search on a collection.
|
|
484
|
+
|
|
485
|
+
**Parameters:**
|
|
486
|
+
|
|
487
|
+
| Parameter | Type | Default | Description |
|
|
488
|
+
|-----------|------|---------|-------------|
|
|
489
|
+
| `collectionName` | string | - | Collection name |
|
|
490
|
+
| `searchText` | string | - | Search query |
|
|
491
|
+
| `limit` | number | 10 | Max results |
|
|
492
|
+
| `scoreThreshold` | number | 0.7 | Min similarity (0-1) |
|
|
493
|
+
|
|
494
|
+
**Usage:**
|
|
495
|
+
```typescript
|
|
496
|
+
const results = await Data.search(
|
|
497
|
+
'movies',
|
|
498
|
+
'sci-fi thriller about dreams',
|
|
499
|
+
5,
|
|
500
|
+
0.8
|
|
501
|
+
);
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
**Returns:**
|
|
505
|
+
```typescript
|
|
506
|
+
{
|
|
507
|
+
data: Array<Entry & { score: number }>;
|
|
508
|
+
count: number;
|
|
509
|
+
}
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
**Similarity Scores:**
|
|
513
|
+
- `1.0` = Perfect match
|
|
514
|
+
- `0.8-0.9` = Very similar
|
|
515
|
+
- `0.6-0.7` = Somewhat similar
|
|
516
|
+
- `<0.6` = Low similarity
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
### `Data.delete(collectionName, entryId)`
|
|
521
|
+
|
|
522
|
+
Deletes an entry.
|
|
523
|
+
|
|
524
|
+
**Usage:**
|
|
525
|
+
```typescript
|
|
526
|
+
await Data.delete('movies', 'entry_abc123');
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
---
|
|
530
|
+
|
|
531
|
+
## Products API
|
|
532
|
+
|
|
533
|
+
Manage product catalog.
|
|
534
|
+
|
|
535
|
+
### `Products.get(limit?, page?)`
|
|
536
|
+
|
|
537
|
+
Retrieves products with pagination.
|
|
538
|
+
|
|
539
|
+
**Usage:**
|
|
540
|
+
```typescript
|
|
541
|
+
const products = await Products.get(20, 1);
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
**Returns:**
|
|
545
|
+
```typescript
|
|
546
|
+
{
|
|
547
|
+
success: boolean;
|
|
548
|
+
data: Product[];
|
|
549
|
+
pagination: {
|
|
550
|
+
currentPage: number;
|
|
551
|
+
totalPages: number;
|
|
552
|
+
totalCount: number;
|
|
553
|
+
hasNextPage: boolean;
|
|
554
|
+
// ...
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
---
|
|
560
|
+
|
|
561
|
+
### `Products.create(product)`
|
|
562
|
+
|
|
563
|
+
Creates a new product.
|
|
564
|
+
|
|
565
|
+
**Usage:**
|
|
566
|
+
```typescript
|
|
567
|
+
const product = await Products.create({
|
|
568
|
+
name: 'Laptop',
|
|
569
|
+
price: 999.99,
|
|
570
|
+
category: 'Electronics',
|
|
571
|
+
sku: 'LAP-001',
|
|
572
|
+
inStock: true
|
|
573
|
+
});
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
**Returns:**
|
|
577
|
+
```typescript
|
|
578
|
+
{
|
|
579
|
+
updated: boolean;
|
|
580
|
+
isNew: boolean;
|
|
581
|
+
product: Product;
|
|
582
|
+
}
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
---
|
|
586
|
+
|
|
587
|
+
### `Products.update(data, id)`
|
|
588
|
+
|
|
589
|
+
Updates an existing product.
|
|
590
|
+
|
|
591
|
+
**Usage:**
|
|
592
|
+
```typescript
|
|
593
|
+
const updated = await Products.update({
|
|
594
|
+
price: 899.99,
|
|
595
|
+
inStock: false
|
|
596
|
+
}, 'product_abc123');
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
---
|
|
600
|
+
|
|
601
|
+
### `Products.delete(id)`
|
|
602
|
+
|
|
603
|
+
Deletes a product.
|
|
604
|
+
|
|
605
|
+
**Usage:**
|
|
606
|
+
```typescript
|
|
607
|
+
await Products.delete('product_abc123');
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
---
|
|
611
|
+
|
|
612
|
+
### `Products.search(query)`
|
|
613
|
+
|
|
614
|
+
Searches products.
|
|
615
|
+
|
|
616
|
+
**Usage:**
|
|
617
|
+
```typescript
|
|
618
|
+
const results = await Products.search('laptop');
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
**Returns:**
|
|
622
|
+
```typescript
|
|
623
|
+
{
|
|
624
|
+
success: boolean;
|
|
625
|
+
data: Product[];
|
|
626
|
+
}
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
---
|
|
630
|
+
|
|
631
|
+
### `Products.getById(id)`
|
|
632
|
+
|
|
633
|
+
Gets a specific product.
|
|
634
|
+
|
|
635
|
+
**Usage:**
|
|
636
|
+
```typescript
|
|
637
|
+
const product = await Products.getById('product_abc123');
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
---
|
|
641
|
+
|
|
642
|
+
## Baskets API
|
|
643
|
+
|
|
644
|
+
Manage shopping baskets.
|
|
645
|
+
|
|
646
|
+
### `Baskets.create(basketData)`
|
|
647
|
+
|
|
648
|
+
Creates a new basket.
|
|
649
|
+
|
|
650
|
+
**Usage:**
|
|
651
|
+
```typescript
|
|
652
|
+
const basket = await Baskets.create({
|
|
653
|
+
currency: 'USD',
|
|
654
|
+
metadata: {
|
|
655
|
+
source: 'web',
|
|
656
|
+
campaign: 'summer_sale'
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
---
|
|
662
|
+
|
|
663
|
+
### `Baskets.get(status?)`
|
|
664
|
+
|
|
665
|
+
Gets baskets, optionally filtered by status.
|
|
666
|
+
|
|
667
|
+
**Usage:**
|
|
668
|
+
```typescript
|
|
669
|
+
// All baskets
|
|
670
|
+
const allBaskets = await Baskets.get();
|
|
671
|
+
|
|
672
|
+
// Active baskets only
|
|
673
|
+
const activeBaskets = await Baskets.get(BasketStatus.ACTIVE);
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
**Basket Statuses:**
|
|
677
|
+
```typescript
|
|
678
|
+
import { BasketStatus } from 'lua-cli';
|
|
679
|
+
|
|
680
|
+
BasketStatus.ACTIVE // Currently being used
|
|
681
|
+
BasketStatus.CHECKED_OUT // Converted to order
|
|
682
|
+
BasketStatus.ABANDONED // User left without checkout
|
|
683
|
+
BasketStatus.EXPIRED // TTL exceeded
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
---
|
|
687
|
+
|
|
688
|
+
### `Baskets.addItem(basketId, itemData)`
|
|
689
|
+
|
|
690
|
+
Adds an item to a basket.
|
|
691
|
+
|
|
692
|
+
**Usage:**
|
|
693
|
+
```typescript
|
|
694
|
+
const updated = await Baskets.addItem('basket_abc123', {
|
|
695
|
+
id: 'product_xyz',
|
|
696
|
+
price: 29.99,
|
|
697
|
+
quantity: 2,
|
|
698
|
+
SKU: 'SHIRT-M-BLUE'
|
|
699
|
+
});
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
---
|
|
703
|
+
|
|
704
|
+
### `Baskets.removeItem(basketId, itemId)`
|
|
705
|
+
|
|
706
|
+
Removes an item from a basket.
|
|
707
|
+
|
|
708
|
+
**Usage:**
|
|
709
|
+
```typescript
|
|
710
|
+
await Baskets.removeItem('basket_abc123', 'item_xyz');
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
---
|
|
714
|
+
|
|
715
|
+
### `Baskets.clear(basketId)`
|
|
716
|
+
|
|
717
|
+
Removes all items from a basket.
|
|
718
|
+
|
|
719
|
+
**Usage:**
|
|
720
|
+
```typescript
|
|
721
|
+
await Baskets.clear('basket_abc123');
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
---
|
|
725
|
+
|
|
726
|
+
### `Baskets.updateStatus(basketId, status)`
|
|
727
|
+
|
|
728
|
+
Updates basket status.
|
|
729
|
+
|
|
730
|
+
**Usage:**
|
|
731
|
+
```typescript
|
|
732
|
+
await Baskets.updateStatus('basket_abc123', BasketStatus.ABANDONED);
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
---
|
|
736
|
+
|
|
737
|
+
### `Baskets.updateMetadata(basketId, metadata)`
|
|
738
|
+
|
|
739
|
+
Updates basket metadata.
|
|
740
|
+
|
|
741
|
+
**Usage:**
|
|
742
|
+
```typescript
|
|
743
|
+
await Baskets.updateMetadata('basket_abc123', {
|
|
744
|
+
notes: 'Gift wrapping requested',
|
|
745
|
+
deliveryDate: '2025-12-25'
|
|
746
|
+
});
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
---
|
|
750
|
+
|
|
751
|
+
### `Baskets.placeOrder(orderData, basketId)`
|
|
752
|
+
|
|
753
|
+
Converts basket to order.
|
|
754
|
+
|
|
755
|
+
**Usage:**
|
|
756
|
+
```typescript
|
|
757
|
+
const order = await Baskets.placeOrder({
|
|
758
|
+
shippingAddress: {
|
|
759
|
+
street: '123 Main St',
|
|
760
|
+
city: 'New York',
|
|
761
|
+
zip: '10001'
|
|
762
|
+
},
|
|
763
|
+
paymentMethod: 'credit_card'
|
|
764
|
+
}, 'basket_abc123');
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
---
|
|
768
|
+
|
|
769
|
+
### `Baskets.getById(basketId)`
|
|
770
|
+
|
|
771
|
+
Gets a specific basket.
|
|
772
|
+
|
|
773
|
+
**Usage:**
|
|
774
|
+
```typescript
|
|
775
|
+
const basket = await Baskets.getById('basket_abc123');
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
---
|
|
779
|
+
|
|
780
|
+
## Orders API
|
|
781
|
+
|
|
782
|
+
Manage orders.
|
|
783
|
+
|
|
784
|
+
### `Orders.create(orderData)`
|
|
785
|
+
|
|
786
|
+
Creates a new order.
|
|
787
|
+
|
|
788
|
+
**Usage:**
|
|
789
|
+
```typescript
|
|
790
|
+
const order = await Orders.create({
|
|
791
|
+
basketId: 'basket_abc123',
|
|
792
|
+
data: {
|
|
793
|
+
shippingAddress: {...},
|
|
794
|
+
paymentMethod: 'stripe'
|
|
795
|
+
}
|
|
796
|
+
});
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
---
|
|
800
|
+
|
|
801
|
+
### `Orders.updateStatus(status, orderId)`
|
|
802
|
+
|
|
803
|
+
Updates order status.
|
|
804
|
+
|
|
805
|
+
**Usage:**
|
|
806
|
+
```typescript
|
|
807
|
+
await Orders.updateStatus(OrderStatus.FULFILLED, 'order_abc123');
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
**Order Statuses:**
|
|
811
|
+
```typescript
|
|
812
|
+
import { OrderStatus } from 'lua-cli';
|
|
813
|
+
|
|
814
|
+
OrderStatus.PENDING // Created, not confirmed
|
|
815
|
+
OrderStatus.CONFIRMED // Confirmed, being processed
|
|
816
|
+
OrderStatus.FULFILLED // Completed and delivered
|
|
817
|
+
OrderStatus.CANCELLED // Cancelled
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
---
|
|
821
|
+
|
|
822
|
+
### `Orders.updateData(data, orderId)`
|
|
823
|
+
|
|
824
|
+
Updates order data.
|
|
825
|
+
|
|
826
|
+
**Usage:**
|
|
827
|
+
```typescript
|
|
828
|
+
await Orders.updateData({
|
|
829
|
+
trackingNumber: 'TRACK123',
|
|
830
|
+
estimatedDelivery: '2025-10-10'
|
|
831
|
+
}, 'order_abc123');
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
---
|
|
835
|
+
|
|
836
|
+
### `Orders.get(status?)`
|
|
837
|
+
|
|
838
|
+
Gets orders, optionally filtered by status.
|
|
839
|
+
|
|
840
|
+
**Usage:**
|
|
841
|
+
```typescript
|
|
842
|
+
// All orders
|
|
843
|
+
const allOrders = await Orders.get();
|
|
844
|
+
|
|
845
|
+
// Pending orders only
|
|
846
|
+
const pending = await Orders.get(OrderStatus.PENDING);
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
---
|
|
850
|
+
|
|
851
|
+
### `Orders.getById(orderId)`
|
|
852
|
+
|
|
853
|
+
Gets a specific order.
|
|
854
|
+
|
|
855
|
+
**Usage:**
|
|
856
|
+
```typescript
|
|
857
|
+
const order = await Orders.getById('order_abc123');
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
---
|
|
861
|
+
|
|
862
|
+
## Environment Variables
|
|
863
|
+
|
|
864
|
+
### `env(key: string): string | undefined`
|
|
865
|
+
|
|
866
|
+
Safely access environment variables.
|
|
867
|
+
|
|
868
|
+
**Usage:**
|
|
869
|
+
```typescript
|
|
870
|
+
import { env } from 'lua-cli';
|
|
871
|
+
|
|
872
|
+
export class MyTool implements LuaTool {
|
|
873
|
+
async execute(input: any) {
|
|
874
|
+
const apiKey = env('EXTERNAL_API_KEY');
|
|
875
|
+
const baseUrl = env('API_BASE_URL') || 'https://default.com';
|
|
876
|
+
|
|
877
|
+
if (!apiKey) {
|
|
878
|
+
throw new Error('EXTERNAL_API_KEY not configured');
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// Use environment variables...
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
```
|
|
885
|
+
|
|
886
|
+
**Loading Priority:**
|
|
887
|
+
1. Process environment variables
|
|
888
|
+
2. `.env` file in project root
|
|
889
|
+
3. `lua.skill.yaml` under `skill.env`
|
|
890
|
+
|
|
891
|
+
**Configuration:**
|
|
892
|
+
|
|
893
|
+
```yaml
|
|
894
|
+
# lua.skill.yaml
|
|
895
|
+
skill:
|
|
896
|
+
env:
|
|
897
|
+
EXTERNAL_API_KEY: sk_abc123
|
|
898
|
+
API_BASE_URL: https://api.example.com
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
Or create `.env` file:
|
|
902
|
+
```bash
|
|
903
|
+
# .env
|
|
904
|
+
EXTERNAL_API_KEY=sk_abc123
|
|
905
|
+
API_BASE_URL=https://api.example.com
|
|
906
|
+
```
|
|
907
|
+
|
|
908
|
+
---
|
|
909
|
+
|
|
910
|
+
## Complete Examples
|
|
911
|
+
|
|
912
|
+
### Example 1: Weather Tool
|
|
913
|
+
|
|
914
|
+
```typescript
|
|
915
|
+
import { LuaTool, env } from 'lua-cli';
|
|
916
|
+
import { z } from 'zod';
|
|
917
|
+
|
|
918
|
+
export default class GetWeatherTool implements LuaTool {
|
|
919
|
+
name = "get_weather";
|
|
920
|
+
description = "Get current weather conditions for any city";
|
|
921
|
+
|
|
922
|
+
inputSchema = z.object({
|
|
923
|
+
city: z.string().describe("City name (e.g., 'London', 'New York')"),
|
|
924
|
+
units: z.enum(['metric', 'imperial']).optional().describe("Temperature units")
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
async execute(input: z.infer<typeof this.inputSchema>) {
|
|
928
|
+
const { city, units = 'metric' } = input;
|
|
929
|
+
|
|
930
|
+
// Call weather API (using free Open-Meteo API)
|
|
931
|
+
const geoUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(city)}&count=1`;
|
|
932
|
+
const geoRes = await fetch(geoUrl);
|
|
933
|
+
const geoData = await geoRes.json();
|
|
934
|
+
|
|
935
|
+
if (!geoData.results?.[0]) {
|
|
936
|
+
throw new Error(`City not found: ${city}`);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
const { latitude, longitude, name } = geoData.results[0];
|
|
940
|
+
|
|
941
|
+
const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t_weather=true&temperature_unit=${units === 'imperial' ? 'fahrenheit' : 'celsius'}`;
|
|
942
|
+
const weatherRes = await fetch(weatherUrl);
|
|
943
|
+
const weatherData = await weatherRes.json();
|
|
944
|
+
|
|
945
|
+
const current = weatherData.current_weather;
|
|
946
|
+
|
|
947
|
+
return {
|
|
948
|
+
city: name,
|
|
949
|
+
temperature: current.temperature,
|
|
950
|
+
windSpeed: current.windspeed,
|
|
951
|
+
condition: current.weathercode
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
---
|
|
958
|
+
|
|
959
|
+
### Example 2: E-commerce Tool
|
|
960
|
+
|
|
961
|
+
```typescript
|
|
962
|
+
import { LuaTool, Products, Baskets } from 'lua-cli';
|
|
963
|
+
import { z } from 'zod';
|
|
964
|
+
|
|
965
|
+
export default class AddToCartTool implements LuaTool {
|
|
966
|
+
name = "add_to_cart";
|
|
967
|
+
description = "Add a product to the shopping cart";
|
|
968
|
+
|
|
969
|
+
inputSchema = z.object({
|
|
970
|
+
productId: z.string().describe("Product ID to add"),
|
|
971
|
+
quantity: z.number().min(1).describe("Quantity to add"),
|
|
972
|
+
basketId: z.string().optional().describe("Existing basket ID (creates new if not provided)")
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
async execute(input: z.infer<typeof this.inputSchema>) {
|
|
976
|
+
const { productId, quantity, basketId } = input;
|
|
977
|
+
|
|
978
|
+
// Get product details
|
|
979
|
+
const product = await Products.getById(productId);
|
|
980
|
+
|
|
981
|
+
// Get or create basket
|
|
982
|
+
let basket;
|
|
983
|
+
if (basketId) {
|
|
984
|
+
basket = await Baskets.getById(basketId);
|
|
985
|
+
} else {
|
|
986
|
+
basket = await Baskets.create({
|
|
987
|
+
currency: 'USD',
|
|
988
|
+
metadata: { source: 'chat' }
|
|
989
|
+
});
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
// Add item to basket
|
|
993
|
+
const updated = await Baskets.addItem(basket.id, {
|
|
994
|
+
id: productId,
|
|
995
|
+
price: product.price,
|
|
996
|
+
quantity: quantity,
|
|
997
|
+
SKU: product.sku
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
return {
|
|
1001
|
+
basketId: updated.id,
|
|
1002
|
+
itemCount: updated.common.itemCount,
|
|
1003
|
+
totalAmount: updated.common.totalAmount,
|
|
1004
|
+
message: `Added ${quantity}x ${product.name} to cart`
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
```
|
|
1009
|
+
|
|
1010
|
+
---
|
|
1011
|
+
|
|
1012
|
+
### Example 3: Custom Data with Search
|
|
1013
|
+
|
|
1014
|
+
```typescript
|
|
1015
|
+
import { LuaTool, Data } from 'lua-cli';
|
|
1016
|
+
import { z } from 'zod';
|
|
1017
|
+
|
|
1018
|
+
export class CreateMovieTool implements LuaTool {
|
|
1019
|
+
name = "create_movie";
|
|
1020
|
+
description = "Add a new movie to the database";
|
|
1021
|
+
|
|
1022
|
+
inputSchema = z.object({
|
|
1023
|
+
title: z.string(),
|
|
1024
|
+
year: z.number(),
|
|
1025
|
+
director: z.string(),
|
|
1026
|
+
genre: z.string()
|
|
1027
|
+
});
|
|
1028
|
+
|
|
1029
|
+
async execute(input: z.infer<typeof this.inputSchema>) {
|
|
1030
|
+
// Create searchable text
|
|
1031
|
+
const searchText = `${input.title} ${input.year} ${input.director} ${input.genre}`;
|
|
1032
|
+
|
|
1033
|
+
const movie = await Data.create('movies', input, searchText);
|
|
1034
|
+
|
|
1035
|
+
return {
|
|
1036
|
+
id: movie.id,
|
|
1037
|
+
message: `Created movie: ${input.title}`
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
export class SearchMoviesTool implements LuaTool {
|
|
1043
|
+
name = "search_movies";
|
|
1044
|
+
description = "Search for movies by title, director, or genre";
|
|
1045
|
+
|
|
1046
|
+
inputSchema = z.object({
|
|
1047
|
+
query: z.string().describe("Search query")
|
|
1048
|
+
});
|
|
1049
|
+
|
|
1050
|
+
async execute(input: z.infer<typeof this.inputSchema>) {
|
|
1051
|
+
const results = await Data.search('movies', input.query, 10, 0.7);
|
|
1052
|
+
|
|
1053
|
+
return {
|
|
1054
|
+
movies: results.data.map(entry => ({
|
|
1055
|
+
id: entry.id,
|
|
1056
|
+
...entry.data,
|
|
1057
|
+
relevance: entry.score
|
|
1058
|
+
})),
|
|
1059
|
+
count: results.count
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
---
|
|
1066
|
+
|
|
1067
|
+
### Example 4: Multi-Step Tool
|
|
1068
|
+
|
|
1069
|
+
```typescript
|
|
1070
|
+
import { LuaTool, Products, Baskets, Orders } from 'lua-cli';
|
|
1071
|
+
import { z } from 'zod';
|
|
1072
|
+
|
|
1073
|
+
export default class QuickCheckoutTool implements LuaTool {
|
|
1074
|
+
name = "quick_checkout";
|
|
1075
|
+
description = "Search for product, add to cart, and create order in one step";
|
|
1076
|
+
|
|
1077
|
+
inputSchema = z.object({
|
|
1078
|
+
productName: z.string(),
|
|
1079
|
+
quantity: z.number().default(1),
|
|
1080
|
+
shippingAddress: z.object({
|
|
1081
|
+
street: z.string(),
|
|
1082
|
+
city: z.string(),
|
|
1083
|
+
zip: z.string()
|
|
1084
|
+
})
|
|
1085
|
+
});
|
|
1086
|
+
|
|
1087
|
+
async execute(input: z.infer<typeof this.inputSchema>) {
|
|
1088
|
+
// Step 1: Search for product
|
|
1089
|
+
const searchResults = await Products.search(input.productName);
|
|
1090
|
+
if (searchResults.data.length === 0) {
|
|
1091
|
+
throw new Error(`Product not found: ${input.productName}`);
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
const product = searchResults.data[0];
|
|
1095
|
+
|
|
1096
|
+
// Step 2: Create basket
|
|
1097
|
+
const basket = await Baskets.create({ currency: 'USD' });
|
|
1098
|
+
|
|
1099
|
+
// Step 3: Add product to basket
|
|
1100
|
+
await Baskets.addItem(basket.id, {
|
|
1101
|
+
id: product.id,
|
|
1102
|
+
price: product.price,
|
|
1103
|
+
quantity: input.quantity
|
|
1104
|
+
});
|
|
1105
|
+
|
|
1106
|
+
// Step 4: Create order
|
|
1107
|
+
const order = await Baskets.placeOrder({
|
|
1108
|
+
shippingAddress: input.shippingAddress,
|
|
1109
|
+
paymentMethod: 'stripe'
|
|
1110
|
+
}, basket.id);
|
|
1111
|
+
|
|
1112
|
+
return {
|
|
1113
|
+
orderId: order.id,
|
|
1114
|
+
product: product.name,
|
|
1115
|
+
quantity: input.quantity,
|
|
1116
|
+
total: basket.common.totalAmount,
|
|
1117
|
+
message: 'Order created successfully'
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
```
|
|
1122
|
+
|
|
1123
|
+
---
|
|
1124
|
+
|
|
1125
|
+
### Example 5: Using Environment Variables
|
|
1126
|
+
|
|
1127
|
+
```typescript
|
|
1128
|
+
import { LuaTool, env } from 'lua-cli';
|
|
1129
|
+
import { z } from 'zod';
|
|
1130
|
+
|
|
1131
|
+
export default class SendEmailTool implements LuaTool {
|
|
1132
|
+
name = "send_email";
|
|
1133
|
+
description = "Send an email via external service";
|
|
1134
|
+
|
|
1135
|
+
inputSchema = z.object({
|
|
1136
|
+
to: z.string().email(),
|
|
1137
|
+
subject: z.string(),
|
|
1138
|
+
body: z.string()
|
|
1139
|
+
});
|
|
1140
|
+
|
|
1141
|
+
async execute(input: z.infer<typeof this.inputSchema>) {
|
|
1142
|
+
// Get API credentials from environment
|
|
1143
|
+
const apiKey = env('SENDGRID_API_KEY');
|
|
1144
|
+
const fromEmail = env('FROM_EMAIL');
|
|
1145
|
+
|
|
1146
|
+
if (!apiKey) {
|
|
1147
|
+
throw new Error('SENDGRID_API_KEY not configured');
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
// Call external API
|
|
1151
|
+
const response = await fetch('https://api.sendgrid.com/v3/mail/send', {
|
|
1152
|
+
method: 'POST',
|
|
1153
|
+
headers: {
|
|
1154
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
1155
|
+
'Content-Type': 'application/json'
|
|
1156
|
+
},
|
|
1157
|
+
body: JSON.stringify({
|
|
1158
|
+
personalizations: [{
|
|
1159
|
+
to: [{ email: input.to }]
|
|
1160
|
+
}],
|
|
1161
|
+
from: { email: fromEmail || 'noreply@example.com' },
|
|
1162
|
+
subject: input.subject,
|
|
1163
|
+
content: [{
|
|
1164
|
+
type: 'text/plain',
|
|
1165
|
+
value: input.body
|
|
1166
|
+
}]
|
|
1167
|
+
})
|
|
1168
|
+
});
|
|
1169
|
+
|
|
1170
|
+
if (!response.ok) {
|
|
1171
|
+
throw new Error(`Email sending failed: ${response.statusText}`);
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
return {
|
|
1175
|
+
success: true,
|
|
1176
|
+
message: `Email sent to ${input.to}`
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
```
|
|
1181
|
+
|
|
1182
|
+
---
|
|
1183
|
+
|
|
1184
|
+
## Type Definitions
|
|
1185
|
+
|
|
1186
|
+
### Importing Types
|
|
1187
|
+
|
|
1188
|
+
```typescript
|
|
1189
|
+
import {
|
|
1190
|
+
LuaSkill,
|
|
1191
|
+
LuaTool,
|
|
1192
|
+
BasketStatus,
|
|
1193
|
+
OrderStatus,
|
|
1194
|
+
env
|
|
1195
|
+
} from 'lua-cli';
|
|
1196
|
+
```
|
|
1197
|
+
|
|
1198
|
+
### Full Type Signature
|
|
1199
|
+
|
|
1200
|
+
```typescript
|
|
1201
|
+
interface LuaTool<TInput extends ZodType = ZodType> {
|
|
1202
|
+
name: string;
|
|
1203
|
+
description: string;
|
|
1204
|
+
inputSchema: TInput;
|
|
1205
|
+
execute: (input: z.infer<TInput>) => Promise<any>;
|
|
1206
|
+
}
|
|
1207
|
+
```
|
|
1208
|
+
|
|
1209
|
+
---
|
|
1210
|
+
|
|
1211
|
+
## Best Practices
|
|
1212
|
+
|
|
1213
|
+
### Tool Design
|
|
1214
|
+
|
|
1215
|
+
**✅ Do:**
|
|
1216
|
+
- Use clear, descriptive names
|
|
1217
|
+
- Write detailed descriptions
|
|
1218
|
+
- Validate all inputs with Zod
|
|
1219
|
+
- Return structured data
|
|
1220
|
+
- Handle errors gracefully
|
|
1221
|
+
- Use environment variables for secrets
|
|
1222
|
+
|
|
1223
|
+
**❌ Don't:**
|
|
1224
|
+
- Use spaces in tool names
|
|
1225
|
+
- Hardcode API keys
|
|
1226
|
+
- Return unstructured strings
|
|
1227
|
+
- Ignore input validation
|
|
1228
|
+
- Swallow errors silently
|
|
1229
|
+
|
|
1230
|
+
---
|
|
1231
|
+
|
|
1232
|
+
### Error Handling
|
|
1233
|
+
|
|
1234
|
+
```typescript
|
|
1235
|
+
async execute(input: any) {
|
|
1236
|
+
try {
|
|
1237
|
+
// Validate business logic
|
|
1238
|
+
if (input.amount <= 0) {
|
|
1239
|
+
throw new Error("Amount must be positive");
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
// Call external service
|
|
1243
|
+
const result = await externalApi.call(input);
|
|
1244
|
+
|
|
1245
|
+
// Validate response
|
|
1246
|
+
if (!result.success) {
|
|
1247
|
+
throw new Error(`API error: ${result.error}`);
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
return result.data;
|
|
1251
|
+
|
|
1252
|
+
} catch (error) {
|
|
1253
|
+
// Add context to errors
|
|
1254
|
+
throw new Error(`Failed to process request: ${error.message}`);
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
```
|
|
1258
|
+
|
|
1259
|
+
---
|
|
1260
|
+
|
|
1261
|
+
### Schema Design
|
|
1262
|
+
|
|
1263
|
+
**Simple and Clear:**
|
|
1264
|
+
```typescript
|
|
1265
|
+
inputSchema = z.object({
|
|
1266
|
+
email: z.string().email().describe("User's email address"),
|
|
1267
|
+
amount: z.number().positive().describe("Amount in USD"),
|
|
1268
|
+
sendReceipt: z.boolean().default(true).describe("Send email receipt")
|
|
1269
|
+
});
|
|
1270
|
+
```
|
|
1271
|
+
|
|
1272
|
+
**With Validation:**
|
|
1273
|
+
```typescript
|
|
1274
|
+
inputSchema = z.object({
|
|
1275
|
+
age: z.number().min(0).max(120),
|
|
1276
|
+
email: z.string().email(),
|
|
1277
|
+
password: z.string().min(8),
|
|
1278
|
+
phone: z.string().regex(/^\+?[1-9]\d{1,14}$/),
|
|
1279
|
+
url: z.string().url()
|
|
1280
|
+
});
|
|
1281
|
+
```
|
|
1282
|
+
|
|
1283
|
+
---
|
|
1284
|
+
|
|
1285
|
+
## Testing Your Skills
|
|
1286
|
+
|
|
1287
|
+
### Local Testing
|
|
1288
|
+
|
|
1289
|
+
```bash
|
|
1290
|
+
# Interactive testing
|
|
1291
|
+
lua test
|
|
1292
|
+
|
|
1293
|
+
# Select tool, enter inputs, see results
|
|
1294
|
+
```
|
|
1295
|
+
|
|
1296
|
+
### Development Mode
|
|
1297
|
+
|
|
1298
|
+
```bash
|
|
1299
|
+
# Start dev mode
|
|
1300
|
+
lua dev
|
|
1301
|
+
|
|
1302
|
+
# Chat interface opens at http://localhost:3000
|
|
1303
|
+
# Edit files - auto-reloads
|
|
1304
|
+
# Test conversational interaction
|
|
1305
|
+
```
|
|
1306
|
+
|
|
1307
|
+
### Production Testing
|
|
1308
|
+
|
|
1309
|
+
```bash
|
|
1310
|
+
# Push to server
|
|
1311
|
+
lua push
|
|
1312
|
+
|
|
1313
|
+
# Test in sandbox before deploying
|
|
1314
|
+
lua dev
|
|
1315
|
+
|
|
1316
|
+
# Deploy when ready
|
|
1317
|
+
lua deploy
|
|
1318
|
+
```
|
|
1319
|
+
|
|
1320
|
+
---
|
|
1321
|
+
|
|
1322
|
+
## TypeScript Support
|
|
1323
|
+
|
|
1324
|
+
All Lua APIs are fully typed:
|
|
1325
|
+
|
|
1326
|
+
```typescript
|
|
1327
|
+
import { User, Products, Data } from 'lua-cli';
|
|
1328
|
+
|
|
1329
|
+
// Autocomplete and type checking work!
|
|
1330
|
+
const user = await User.get(); // user is typed
|
|
1331
|
+
const products = await Products.get(); // products is typed
|
|
1332
|
+
const data = await Data.get('movies'); // data is typed
|
|
1333
|
+
```
|
|
1334
|
+
|
|
1335
|
+
---
|
|
1336
|
+
|
|
1337
|
+
## Common Patterns
|
|
1338
|
+
|
|
1339
|
+
### Pattern: Conditional Tool Execution
|
|
1340
|
+
|
|
1341
|
+
```typescript
|
|
1342
|
+
async execute(input: any) {
|
|
1343
|
+
if (input.query) {
|
|
1344
|
+
// Search path
|
|
1345
|
+
return await Products.search(input.query);
|
|
1346
|
+
} else {
|
|
1347
|
+
// List all path
|
|
1348
|
+
return await Products.get(20, 1);
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
```
|
|
1352
|
+
|
|
1353
|
+
### Pattern: Data Transformation
|
|
1354
|
+
|
|
1355
|
+
```typescript
|
|
1356
|
+
async execute(input: any) {
|
|
1357
|
+
const products = await Products.get(100);
|
|
1358
|
+
|
|
1359
|
+
// Transform for AI consumption
|
|
1360
|
+
return products.data.map(p => ({
|
|
1361
|
+
name: p.name,
|
|
1362
|
+
price: `$${p.price}`,
|
|
1363
|
+
available: p.inStock ? 'Yes' : 'No'
|
|
1364
|
+
}));
|
|
1365
|
+
}
|
|
1366
|
+
```
|
|
1367
|
+
|
|
1368
|
+
### Pattern: Error Recovery
|
|
1369
|
+
|
|
1370
|
+
```typescript
|
|
1371
|
+
async execute(input: any) {
|
|
1372
|
+
try {
|
|
1373
|
+
return await externalApi.call(input);
|
|
1374
|
+
} catch (error) {
|
|
1375
|
+
// Fallback behavior
|
|
1376
|
+
console.warn('External API failed, using fallback');
|
|
1377
|
+
return await fallbackService.call(input);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
```
|
|
1381
|
+
|
|
1382
|
+
---
|
|
1383
|
+
|
|
1384
|
+
## Limits and Quotas
|
|
1385
|
+
|
|
1386
|
+
- **Vector Search**: `scoreThreshold` 0-1 (0.7 recommended minimum)
|
|
1387
|
+
- **Pagination**: Default 10 items, max 100 per page
|
|
1388
|
+
- **Tool Names**: 1-50 characters, alphanumeric + `-` `_` only
|
|
1389
|
+
- **Data Storage**: No hard limits on custom data collections
|
|
1390
|
+
|
|
1391
|
+
---
|
|
1392
|
+
|
|
1393
|
+
## Additional Resources
|
|
1394
|
+
|
|
1395
|
+
- **CLI Commands**: See `CLI_REFERENCE.md`
|
|
1396
|
+
- **Template Guide**: See `TEMPLATE_GUIDE.md`
|
|
1397
|
+
- **Development**: See `DEVELOPER_GUIDE.md`
|
|
1398
|
+
- **Examples**: Check `template/src/tools/` directory
|
|
1399
|
+
- **Platform Docs**: https://docs.lua.ai
|
|
1400
|
+
|
|
1401
|
+
---
|
|
1402
|
+
|
|
1403
|
+
## Support
|
|
1404
|
+
|
|
1405
|
+
- **Issues**: https://github.com/lua-ai/lua-cli/issues
|
|
1406
|
+
- **Docs**: https://docs.lua.ai
|
|
1407
|
+
- **Email**: support@lua.ai
|
|
1408
|
+
|