lua-cli 3.0.0-alpha.1 → 3.0.0-alpha.5
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/api/job.api.service.d.ts +16 -7
- package/dist/api/job.api.service.js +21 -5
- package/dist/api/postprocessor.api.service.d.ts +61 -1
- package/dist/api/postprocessor.api.service.js +35 -0
- package/dist/api/preprocessor.api.service.d.ts +61 -1
- package/dist/api/preprocessor.api.service.js +35 -0
- package/dist/api-exports.d.ts +26 -6
- package/dist/api-exports.js +42 -29
- package/dist/cli/command-definitions.js +13 -6
- package/dist/commands/chat.js +32 -5
- package/dist/commands/compile.js +16 -2
- package/dist/commands/dev.js +23 -2
- package/dist/commands/push.d.ts +6 -2
- package/dist/commands/push.js +412 -6
- package/dist/commands/test.js +18 -2
- package/dist/common/job.instance.d.ts +3 -0
- package/dist/common/job.instance.js +8 -0
- package/dist/config/constants.d.ts +6 -5
- package/dist/config/constants.js +12 -10
- package/dist/interfaces/chat.d.ts +30 -1
- package/dist/interfaces/jobs.d.ts +21 -0
- package/dist/types/skill.d.ts +75 -56
- package/dist/types/skill.js +53 -59
- package/dist/utils/bundling.d.ts +13 -4
- package/dist/utils/bundling.js +83 -26
- package/dist/utils/compile.js +27 -6
- package/dist/utils/dev-api.d.ts +42 -2
- package/dist/utils/dev-api.js +177 -4
- package/dist/utils/dev-server.d.ts +1 -1
- package/dist/utils/dev-server.js +4 -4
- package/dist/utils/dynamic-job-bundler.d.ts +17 -0
- package/dist/utils/dynamic-job-bundler.js +143 -0
- package/dist/utils/pre-bundle-jobs.d.ts +26 -0
- package/dist/utils/pre-bundle-jobs.js +176 -0
- package/dist/utils/sandbox-storage.d.ts +48 -0
- package/dist/utils/sandbox-storage.js +114 -0
- package/dist/utils/sandbox.d.ts +2 -2
- package/dist/utils/sandbox.js +23 -7
- package/package.json +1 -1
- package/template/lua.skill.yaml +47 -0
- package/template/package-lock.json +10505 -0
- package/template/package.json +2 -1
- package/template/src/index.ts +65 -3
- package/template/src/tools/CreateInlineJob.ts +42 -0
- package/API_REFERENCE.md +0 -1408
- package/CHANGELOG.md +0 -236
- package/CLI_REFERENCE.md +0 -908
- package/GETTING_STARTED.md +0 -1040
- package/INSTANCE_TYPES.md +0 -1158
- package/README.md +0 -865
- package/TEMPLATE_GUIDE.md +0 -1398
- package/USER_DATA_INSTANCE.md +0 -621
- package/template/AGENT_CONFIGURATION.md +0 -251
- package/template/COMPLEX_JOB_EXAMPLES.md +0 -795
- package/template/DYNAMIC_JOB_CREATION.md +0 -371
- package/template/TOOL_EXAMPLES.md +0 -655
- package/template/WEBHOOKS_JOBS_QUICKSTART.md +0 -318
- package/template/WEBHOOK_JOB_EXAMPLES.md +0 -817
- package/template/src/index-agent-example.ts +0 -201
- package/template/src/postprocessors/ResponseFormatter.ts +0 -151
- package/template/src/preprocessors/MessageFilter.ts +0 -91
|
@@ -1,371 +0,0 @@
|
|
|
1
|
-
# Dynamic Job Creation from Tools
|
|
2
|
-
|
|
3
|
-
**Question:** Why doesn't the SmartBasketTool actually create a job?
|
|
4
|
-
|
|
5
|
-
**Answer:** There are **two approaches** for scheduling future tasks from tools. The example shows both!
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## 🎯 Two Approaches Explained
|
|
10
|
-
|
|
11
|
-
### **Approach 1: Data-Based Scheduling** ✅ (Currently Implemented)
|
|
12
|
-
|
|
13
|
-
**How it works:**
|
|
14
|
-
1. Tool stores reminder data in custom data collection
|
|
15
|
-
2. A recurring job checks for due reminders
|
|
16
|
-
3. When time comes, job processes the reminder
|
|
17
|
-
|
|
18
|
-
**Pros:**
|
|
19
|
-
- ✅ Simple to implement
|
|
20
|
-
- ✅ No dynamic job creation needed
|
|
21
|
-
- ✅ Works now (no backend changes required)
|
|
22
|
-
- ✅ Easy to manage (single recurring job)
|
|
23
|
-
|
|
24
|
-
**Cons:**
|
|
25
|
-
- ⚠️ Requires a recurring job to run frequently
|
|
26
|
-
- ⚠️ Less precise timing (depends on job interval)
|
|
27
|
-
- ⚠️ More database queries
|
|
28
|
-
|
|
29
|
-
**Code:**
|
|
30
|
-
```typescript
|
|
31
|
-
// In the tool:
|
|
32
|
-
await Data.create('basket-reminders', {
|
|
33
|
-
basketId: basket.id,
|
|
34
|
-
scheduledFor: checkTime.toISOString(),
|
|
35
|
-
status: 'pending'
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// Separate recurring job (every 15 minutes):
|
|
39
|
-
const reminders = await Data.get('basket-reminders', {});
|
|
40
|
-
for (const reminder of reminders) {
|
|
41
|
-
if (new Date(reminder.scheduledFor) <= now) {
|
|
42
|
-
// Process reminder
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
### **Approach 2: Dynamic Job Creation** 🚀 (Advanced - Commented Out)
|
|
50
|
-
|
|
51
|
-
**How it works:**
|
|
52
|
-
1. Tool creates a one-time job via API
|
|
53
|
-
2. Backend scheduler runs the job at exact time
|
|
54
|
-
3. Job executes once and auto-deactivates
|
|
55
|
-
|
|
56
|
-
**Pros:**
|
|
57
|
-
- ✅ Precise timing (exact execution time)
|
|
58
|
-
- ✅ No polling/recurring job needed
|
|
59
|
-
- ✅ Each task is isolated
|
|
60
|
-
- ✅ Auto-cleanup after execution
|
|
61
|
-
|
|
62
|
-
**Cons:**
|
|
63
|
-
- ⚠️ Requires backend API support (create jobs endpoint)
|
|
64
|
-
- ⚠️ More complex implementation
|
|
65
|
-
- ⚠️ More jobs in system (one per basket)
|
|
66
|
-
|
|
67
|
-
**Code (when backend supports it):**
|
|
68
|
-
```typescript
|
|
69
|
-
// Create job dynamically
|
|
70
|
-
const jobPayload = {
|
|
71
|
-
name: `check-basket-${basket.id}`,
|
|
72
|
-
schedule: {
|
|
73
|
-
type: 'once',
|
|
74
|
-
executeAt: checkTime.toISOString()
|
|
75
|
-
},
|
|
76
|
-
executeFunction: `
|
|
77
|
-
async () => {
|
|
78
|
-
const basket = await Baskets.getById('${basket.id}');
|
|
79
|
-
if (basket.status === 'active') {
|
|
80
|
-
// Send reminder
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
`
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
await fetch('/developer/jobs/{agentId}', {
|
|
87
|
-
method: 'POST',
|
|
88
|
-
body: JSON.stringify(jobPayload)
|
|
89
|
-
});
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## 📊 Comparison
|
|
95
|
-
|
|
96
|
-
| Feature | Approach 1 (Data-Based) | Approach 2 (Dynamic Jobs) |
|
|
97
|
-
|---------|------------------------|---------------------------|
|
|
98
|
-
| **Complexity** | ⭐ Simple | ⭐⭐⭐ Complex |
|
|
99
|
-
| **Timing Precision** | ~15 minutes | Exact |
|
|
100
|
-
| **Backend Support** | ✅ Available now | ⏳ Coming soon |
|
|
101
|
-
| **Jobs Created** | 1 recurring | 1 per basket |
|
|
102
|
-
| **Database Queries** | High | Low |
|
|
103
|
-
| **Best For** | Most use cases | High-precision timing |
|
|
104
|
-
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
## 🎯 When to Use Each Approach
|
|
108
|
-
|
|
109
|
-
### Use Approach 1 (Data-Based) When:
|
|
110
|
-
- ✅ Timing doesn't need to be exact (±15 minutes is fine)
|
|
111
|
-
- ✅ You have many similar scheduled tasks
|
|
112
|
-
- ✅ You want simpler code
|
|
113
|
-
- ✅ Backend doesn't support dynamic job creation yet
|
|
114
|
-
|
|
115
|
-
**Examples:**
|
|
116
|
-
- Abandoned cart reminders (3 hours ± 15 min is fine)
|
|
117
|
-
- Follow-up emails (24 hours ± 15 min is fine)
|
|
118
|
-
- Subscription renewals (checking daily is fine)
|
|
119
|
-
|
|
120
|
-
### Use Approach 2 (Dynamic Jobs) When:
|
|
121
|
-
- ✅ Timing must be exact
|
|
122
|
-
- ✅ Each task is unique
|
|
123
|
-
- ✅ You want isolated execution
|
|
124
|
-
- ✅ Backend supports job creation API
|
|
125
|
-
|
|
126
|
-
**Examples:**
|
|
127
|
-
- Scheduled content publishing (must be exact time)
|
|
128
|
-
- Billing cycles (must be precise)
|
|
129
|
-
- Auction endings (exact second matters)
|
|
130
|
-
- Appointment reminders (exact timing important)
|
|
131
|
-
|
|
132
|
-
---
|
|
133
|
-
|
|
134
|
-
## 🔧 Implementation Details
|
|
135
|
-
|
|
136
|
-
### Approach 1: Complete Flow
|
|
137
|
-
|
|
138
|
-
**Step 1 - Tool stores reminder:**
|
|
139
|
-
```typescript
|
|
140
|
-
// SmartBasketTool.ts
|
|
141
|
-
await Data.create('basket-reminders', {
|
|
142
|
-
basketId: basket.id,
|
|
143
|
-
scheduledFor: new Date(Date.now() + 3 * 60 * 60 * 1000).toISOString(),
|
|
144
|
-
status: 'pending'
|
|
145
|
-
});
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
**Step 2 - Recurring job processes reminders:**
|
|
149
|
-
```typescript
|
|
150
|
-
// AbandonedBasketProcessorJob.ts
|
|
151
|
-
const job = new LuaJob({
|
|
152
|
-
name: "process-basket-reminders",
|
|
153
|
-
schedule: {
|
|
154
|
-
type: 'interval',
|
|
155
|
-
seconds: 900 // Every 15 minutes
|
|
156
|
-
},
|
|
157
|
-
execute: async () => {
|
|
158
|
-
const reminders = await Data.get('basket-reminders', {});
|
|
159
|
-
const now = new Date();
|
|
160
|
-
|
|
161
|
-
for (const reminder of reminders) {
|
|
162
|
-
if (new Date(reminder.scheduledFor) <= now && reminder.status === 'pending') {
|
|
163
|
-
// Check basket and send reminder if abandoned
|
|
164
|
-
const basket = await Baskets.getById(reminder.basketId);
|
|
165
|
-
|
|
166
|
-
if (basket.status === 'active') {
|
|
167
|
-
// Send reminder
|
|
168
|
-
console.log(`📧 Sending reminder for basket ${basket.id}`);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Mark as processed
|
|
172
|
-
await Data.update('basket-reminders', reminder.id, { status: 'completed' });
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
---
|
|
180
|
-
|
|
181
|
-
### Approach 2: Complete Flow (When Available)
|
|
182
|
-
|
|
183
|
-
**Step 1 - Tool creates job via API:**
|
|
184
|
-
```typescript
|
|
185
|
-
// SmartBasketTool.ts
|
|
186
|
-
const jobPayload = {
|
|
187
|
-
name: `check-basket-${basket.id}`,
|
|
188
|
-
description: `Check basket ${basket.id}`,
|
|
189
|
-
schedule: {
|
|
190
|
-
type: 'once',
|
|
191
|
-
executeAt: new Date(Date.now() + 3 * 60 * 60 * 1000).toISOString()
|
|
192
|
-
},
|
|
193
|
-
executeFunction: `
|
|
194
|
-
async () => {
|
|
195
|
-
const basket = await Baskets.getById('${basket.id}');
|
|
196
|
-
if (basket.status === 'active') {
|
|
197
|
-
await Data.create('abandoned-baskets', { basketId: '${basket.id}' });
|
|
198
|
-
// Send reminder
|
|
199
|
-
}
|
|
200
|
-
return { checked: true };
|
|
201
|
-
}
|
|
202
|
-
`
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
// Create job
|
|
206
|
-
const response = await fetch(`/developer/jobs/{agentId}`, {
|
|
207
|
-
method: 'POST',
|
|
208
|
-
headers: { 'Authorization': `Bearer ${apiKey}` },
|
|
209
|
-
body: JSON.stringify(jobPayload)
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
const job = await response.json();
|
|
213
|
-
|
|
214
|
-
// Push version to activate it
|
|
215
|
-
await fetch(`/developer/jobs/{agentId}/${job.id}/version`, {
|
|
216
|
-
method: 'POST',
|
|
217
|
-
body: JSON.stringify({ ...jobPayload, version: '1.0.0', jobId: job.id })
|
|
218
|
-
});
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
**Step 2 - Backend scheduler:**
|
|
222
|
-
- Job is created and scheduled
|
|
223
|
-
- At exactly 3 hours later, job executes
|
|
224
|
-
- Job runs once and auto-deactivates
|
|
225
|
-
- Result is logged in execution history
|
|
226
|
-
|
|
227
|
-
---
|
|
228
|
-
|
|
229
|
-
## 🚀 Current Implementation (Approach 1)
|
|
230
|
-
|
|
231
|
-
The `SmartBasketTool` currently uses **Approach 1** because:
|
|
232
|
-
|
|
233
|
-
1. ✅ **Works immediately** - No backend changes needed
|
|
234
|
-
2. ✅ **Simple** - Easy to understand and maintain
|
|
235
|
-
3. ✅ **Sufficient** - 15-minute precision is fine for cart reminders
|
|
236
|
-
4. ✅ **Scalable** - One job handles all baskets
|
|
237
|
-
|
|
238
|
-
**Files involved:**
|
|
239
|
-
- `src/tools/SmartBasketTool.ts` - Creates basket + stores reminder
|
|
240
|
-
- `src/jobs/AbandonedBasketProcessorJob.ts` - Processes reminders every 15 min
|
|
241
|
-
|
|
242
|
-
**To enable:**
|
|
243
|
-
```typescript
|
|
244
|
-
// In src/index.ts
|
|
245
|
-
import { CreateSmartBasketTool } from "./tools/SmartBasketTool";
|
|
246
|
-
import abandonedBasketProcessorJob from "./jobs/AbandonedBasketProcessorJob";
|
|
247
|
-
|
|
248
|
-
const basketSkill = new LuaSkill({
|
|
249
|
-
tools: [new CreateSmartBasketTool()]
|
|
250
|
-
});
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
---
|
|
254
|
-
|
|
255
|
-
## 🔮 Future: Approach 2 (When Backend Ready)
|
|
256
|
-
|
|
257
|
-
When the backend implements dynamic job creation API, you can:
|
|
258
|
-
|
|
259
|
-
1. **Uncomment Approach 2** in `SmartBasketTool.ts`
|
|
260
|
-
2. **Remove the data-based reminder** code
|
|
261
|
-
3. **Remove the recurring processor job** (no longer needed)
|
|
262
|
-
|
|
263
|
-
**Benefits:**
|
|
264
|
-
- Jobs execute at **exact** 3-hour mark
|
|
265
|
-
- No recurring job needed
|
|
266
|
-
- Each basket gets its own isolated job
|
|
267
|
-
- Automatic cleanup after execution
|
|
268
|
-
|
|
269
|
-
---
|
|
270
|
-
|
|
271
|
-
## 💡 Hybrid Approach (Best of Both Worlds)
|
|
272
|
-
|
|
273
|
-
You can also combine both approaches:
|
|
274
|
-
|
|
275
|
-
```typescript
|
|
276
|
-
async execute(input: { currency: string }) {
|
|
277
|
-
const basket = await Baskets.create({ currency: input.currency });
|
|
278
|
-
|
|
279
|
-
// Approach 1: Quick fallback (works now)
|
|
280
|
-
await Data.create('basket-reminders', {
|
|
281
|
-
basketId: basket.id,
|
|
282
|
-
scheduledFor: checkTime.toISOString()
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
// Approach 2: Try dynamic job (if backend supports it)
|
|
286
|
-
try {
|
|
287
|
-
const jobResponse = await createDynamicJob(basket.id, checkTime);
|
|
288
|
-
if (jobResponse.ok) {
|
|
289
|
-
// Dynamic job created - mark data reminder as redundant
|
|
290
|
-
await Data.update('basket-reminders', reminder.id, {
|
|
291
|
-
status: 'delegated-to-job'
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
} catch (error) {
|
|
295
|
-
// Fall back to approach 1 (already stored)
|
|
296
|
-
console.log('Using data-based reminder (dynamic jobs not available)');
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
return { success: true, basket };
|
|
300
|
-
}
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
---
|
|
304
|
-
|
|
305
|
-
## 📋 Summary
|
|
306
|
-
|
|
307
|
-
### Current State ✅
|
|
308
|
-
- ✅ **SmartBasketTool** stores reminders in data
|
|
309
|
-
- ✅ **AbandonedBasketProcessorJob** processes them every 15 minutes
|
|
310
|
-
- ✅ **Works perfectly** for abandoned cart recovery
|
|
311
|
-
- ✅ **No backend changes needed**
|
|
312
|
-
|
|
313
|
-
### Why No Real Job Created?
|
|
314
|
-
Because **Approach 1 is simpler and sufficient** for most use cases!
|
|
315
|
-
|
|
316
|
-
### When Will Approach 2 Work?
|
|
317
|
-
When backend implements:
|
|
318
|
-
- `POST /developer/jobs/{agentId}` - Create job endpoint
|
|
319
|
-
- `POST /developer/jobs/{agentId}/{jobId}/version` - Push job version
|
|
320
|
-
|
|
321
|
-
Then you can uncomment the code in lines 65-134 of `SmartBasketTool.ts`!
|
|
322
|
-
|
|
323
|
-
---
|
|
324
|
-
|
|
325
|
-
## 🎓 Teaching Point
|
|
326
|
-
|
|
327
|
-
This example teaches an important pattern:
|
|
328
|
-
|
|
329
|
-
> **"Not every future task needs a separate job!"**
|
|
330
|
-
|
|
331
|
-
Sometimes storing data and processing it with a recurring job is:
|
|
332
|
-
- Simpler
|
|
333
|
-
- More efficient
|
|
334
|
-
- Easier to manage
|
|
335
|
-
- Perfectly adequate
|
|
336
|
-
|
|
337
|
-
**Use dynamic job creation when you truly need precision timing.**
|
|
338
|
-
|
|
339
|
-
---
|
|
340
|
-
|
|
341
|
-
## 🚀 Try It Out
|
|
342
|
-
|
|
343
|
-
```bash
|
|
344
|
-
# 1. Enable the example
|
|
345
|
-
# Uncomment in src/index.ts:
|
|
346
|
-
# - CreateSmartBasketTool
|
|
347
|
-
# - AbandonedBasketProcessorJob
|
|
348
|
-
|
|
349
|
-
# 2. Compile
|
|
350
|
-
lua compile
|
|
351
|
-
|
|
352
|
-
# 3. Test the tool
|
|
353
|
-
lua test skill
|
|
354
|
-
# Select: create_smart_basket
|
|
355
|
-
# See: Basket created + reminder stored
|
|
356
|
-
|
|
357
|
-
# 4. Test the processor job
|
|
358
|
-
lua test job
|
|
359
|
-
# Select: process-basket-reminders
|
|
360
|
-
# See: Reminders checked and processed
|
|
361
|
-
|
|
362
|
-
# 5. Deploy both
|
|
363
|
-
lua push skill
|
|
364
|
-
lua push job
|
|
365
|
-
lua jobs production # Activate processor job
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
---
|
|
369
|
-
|
|
370
|
-
**The system is designed to work today, with an upgrade path to dynamic jobs in the future!** 🎯
|
|
371
|
-
|