lua-cli 3.0.0-alpha.8 → 3.0.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/README.md +850 -0
- package/dist/api/chat.api.service.d.ts +8 -0
- package/dist/api/chat.api.service.js +55 -0
- package/dist/api/products.api.service.d.ts +2 -1
- package/dist/api/products.api.service.js +11 -10
- package/dist/api-exports.d.ts +1 -1
- package/dist/api-exports.js +6 -1
- package/dist/commands/chat.js +39 -34
- package/dist/commands/init.js +10 -2
- package/dist/index.js +2 -2
- package/dist/interfaces/message.d.ts +2 -2
- package/dist/utils/agent-management.d.ts +1 -1
- package/dist/utils/agent-management.js +5 -3
- package/dist/utils/init-helpers.d.ts +10 -1
- package/dist/utils/init-helpers.js +44 -1
- package/dist/utils/pre-bundle-jobs.js +9 -9
- package/dist/utils/sandbox.js +1 -2
- package/package.json +3 -3
- package/template/QUICKSTART.md +693 -191
- package/template/README.md +673 -802
- package/template/lua.skill.yaml +6 -28
- package/template/package.json +1 -1
- package/template/src/index.ts +18 -252
- package/template/src/postprocessors/modifyResponse.ts +21 -0
- package/template/src/preprocessors/messageMatching.ts +22 -0
- package/template/src/skills/basket.skill.ts +12 -0
- package/template/src/skills/product.skill.ts +13 -0
- package/template/src/{tools → skills/tools}/ProductsTool.ts +2 -1
- package/template/src/skills/tools/UserDataTool.ts +75 -0
- package/template/src/skills/user.skill.ts +13 -0
- package/template/src/seed.ts +0 -46
- package/template/src/tools/UserDataTool.ts +0 -33
- /package/template/src/{tools → skills/tools}/BasketTool.ts +0 -0
- /package/template/src/{tools → skills/tools}/CreateInlineJob.ts +0 -0
- /package/template/src/{tools → skills/tools}/CreatePostTool.ts +0 -0
- /package/template/src/{tools → skills/tools}/CustomDataTool.ts +0 -0
- /package/template/src/{tools → skills/tools}/GameScoreTrackerTool.ts +0 -0
- /package/template/src/{tools → skills/tools}/GetWeatherTool.ts +0 -0
- /package/template/src/{tools → skills/tools}/OrderTool.ts +0 -0
- /package/template/src/{tools → skills/tools}/PaymentTool.ts +0 -0
- /package/template/src/{tools → skills/tools}/SmartBasketTool.ts +0 -0
|
@@ -18,4 +18,12 @@ export default class ChatApi extends HttpClient {
|
|
|
18
18
|
* @throws Error if the agent is not found or the chat request fails
|
|
19
19
|
*/
|
|
20
20
|
sendMessage(agentId: string, chatData: ChatRequest): Promise<ApiResponse<ChatResponse>>;
|
|
21
|
+
/**
|
|
22
|
+
* Streams a message to an agent and receives chunked responses
|
|
23
|
+
* @param agentId - The unique identifier of the agent to chat with
|
|
24
|
+
* @param chatData - The chat request data including message, conversation history, and context
|
|
25
|
+
* @param onChunk - Callback function to handle each text chunk as it arrives
|
|
26
|
+
* @returns Promise resolving when stream completes
|
|
27
|
+
*/
|
|
28
|
+
sendMessageStream(agentId: string, chatData: ChatRequest, onChunk: (text: string) => void): Promise<void>;
|
|
21
29
|
}
|
|
@@ -21,4 +21,59 @@ export default class ChatApi extends HttpClient {
|
|
|
21
21
|
Authorization: `Bearer ${this.apiKey}`,
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Streams a message to an agent and receives chunked responses
|
|
26
|
+
* @param agentId - The unique identifier of the agent to chat with
|
|
27
|
+
* @param chatData - The chat request data including message, conversation history, and context
|
|
28
|
+
* @param onChunk - Callback function to handle each text chunk as it arrives
|
|
29
|
+
* @returns Promise resolving when stream completes
|
|
30
|
+
*/
|
|
31
|
+
async sendMessageStream(agentId, chatData, onChunk) {
|
|
32
|
+
const response = await fetch(`${this.baseUrl}/chat/stream/${agentId}?channel=dev`, {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
headers: {
|
|
35
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
|
+
},
|
|
38
|
+
body: JSON.stringify(chatData)
|
|
39
|
+
});
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
42
|
+
}
|
|
43
|
+
if (!response.body) {
|
|
44
|
+
throw new Error('Response body is not readable');
|
|
45
|
+
}
|
|
46
|
+
const reader = response.body.getReader();
|
|
47
|
+
const decoder = new TextDecoder();
|
|
48
|
+
let buffer = '';
|
|
49
|
+
try {
|
|
50
|
+
while (true) {
|
|
51
|
+
const { done, value } = await reader.read();
|
|
52
|
+
if (done)
|
|
53
|
+
break;
|
|
54
|
+
// Decode the chunk and add to buffer
|
|
55
|
+
buffer += decoder.decode(value, { stream: true });
|
|
56
|
+
// Process complete lines (chunks are separated by newlines)
|
|
57
|
+
const lines = buffer.split('\n');
|
|
58
|
+
buffer = lines.pop() || ''; // Keep incomplete line in buffer
|
|
59
|
+
for (const line of lines) {
|
|
60
|
+
if (!line.trim())
|
|
61
|
+
continue;
|
|
62
|
+
try {
|
|
63
|
+
const chunk = JSON.parse(line);
|
|
64
|
+
// Only process text-delta chunks and call onChunk immediately
|
|
65
|
+
if (chunk.type === 'text-delta' && chunk.textDelta) {
|
|
66
|
+
onChunk(chunk.textDelta);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
// Skip invalid JSON lines
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
reader.releaseLock();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
24
79
|
}
|
|
@@ -59,8 +59,9 @@ export default class ProductApi extends HttpClient implements ProductAPI {
|
|
|
59
59
|
/**
|
|
60
60
|
* Performs semantic search on products using a text query
|
|
61
61
|
* @param searchQuery - The search text to find matching products
|
|
62
|
+
* @param limit - The maximum number of products to return (default: 5)
|
|
62
63
|
* @returns Promise resolving to a ProductSearchInstance containing search results
|
|
63
64
|
* @throws Error if the search fails or the API request is unsuccessful
|
|
64
65
|
*/
|
|
65
|
-
search(searchQuery: string): Promise<ProductSearchInstance>;
|
|
66
|
+
search(searchQuery: string, limit?: number): Promise<ProductSearchInstance>;
|
|
66
67
|
}
|
|
@@ -25,16 +25,16 @@ export default class ProductApi extends HttpClient {
|
|
|
25
25
|
* @throws Error if the request fails or products cannot be retrieved
|
|
26
26
|
*/
|
|
27
27
|
async get(page = 1, limit = 10) {
|
|
28
|
-
console.log(
|
|
28
|
+
console.log("get products", page, limit, this.agentId, this.apiKey);
|
|
29
29
|
const response = await this.httpGet(`/developer/agents/${this.agentId}/products?page=${page}&limit=${limit}`, {
|
|
30
30
|
Authorization: `Bearer ${this.apiKey}`,
|
|
31
31
|
});
|
|
32
|
-
console.log(
|
|
32
|
+
console.log("get products response", response);
|
|
33
33
|
if (response.success) {
|
|
34
34
|
return new ProductPaginationInstance(this, response);
|
|
35
35
|
}
|
|
36
36
|
console.error(response);
|
|
37
|
-
throw new Error(response.error?.message ||
|
|
37
|
+
throw new Error(response.error?.message || "Failed to get products");
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
40
|
* Retrieves a single product by its unique identifier
|
|
@@ -49,7 +49,7 @@ export default class ProductApi extends HttpClient {
|
|
|
49
49
|
if (response.success && response.data) {
|
|
50
50
|
return new ProductInstance(this, response.data);
|
|
51
51
|
}
|
|
52
|
-
throw new Error(response.error?.message ||
|
|
52
|
+
throw new Error(response.error?.message || "Failed to get product");
|
|
53
53
|
}
|
|
54
54
|
/**
|
|
55
55
|
* Creates a new product in the agent's catalog
|
|
@@ -64,7 +64,7 @@ export default class ProductApi extends HttpClient {
|
|
|
64
64
|
if (response.success && response.data) {
|
|
65
65
|
return new ProductInstance(this, response.data.product);
|
|
66
66
|
}
|
|
67
|
-
throw new Error(response.error?.message ||
|
|
67
|
+
throw new Error(response.error?.message || "Failed to create product");
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
70
70
|
* Updates an existing product's information
|
|
@@ -80,7 +80,7 @@ export default class ProductApi extends HttpClient {
|
|
|
80
80
|
if (response.success) {
|
|
81
81
|
return response.data;
|
|
82
82
|
}
|
|
83
|
-
throw new Error(response.error?.message ||
|
|
83
|
+
throw new Error(response.error?.message || "Failed to update product");
|
|
84
84
|
}
|
|
85
85
|
/**
|
|
86
86
|
* Deletes a product from the agent's catalog
|
|
@@ -95,21 +95,22 @@ export default class ProductApi extends HttpClient {
|
|
|
95
95
|
if (response.success) {
|
|
96
96
|
return response.data;
|
|
97
97
|
}
|
|
98
|
-
throw new Error(response.error?.message ||
|
|
98
|
+
throw new Error(response.error?.message || "Failed to delete product");
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
101
|
* Performs semantic search on products using a text query
|
|
102
102
|
* @param searchQuery - The search text to find matching products
|
|
103
|
+
* @param limit - The maximum number of products to return (default: 5)
|
|
103
104
|
* @returns Promise resolving to a ProductSearchInstance containing search results
|
|
104
105
|
* @throws Error if the search fails or the API request is unsuccessful
|
|
105
106
|
*/
|
|
106
|
-
async search(searchQuery) {
|
|
107
|
-
const response = await this.httpGet(`/developer/agents/${this.agentId}/products/search?searchQuery=${encodeURIComponent(searchQuery)}`, {
|
|
107
|
+
async search(searchQuery, limit = 5) {
|
|
108
|
+
const response = await this.httpGet(`/developer/agents/${this.agentId}/products/search?searchQuery=${encodeURIComponent(searchQuery)}&limit=${limit}`, {
|
|
108
109
|
Authorization: `Bearer ${this.apiKey}`,
|
|
109
110
|
});
|
|
110
111
|
if (response.success) {
|
|
111
112
|
return new ProductSearchInstance(this, response);
|
|
112
113
|
}
|
|
113
|
-
throw new Error(response.error?.message ||
|
|
114
|
+
throw new Error(response.error?.message || "Failed to search products");
|
|
114
115
|
}
|
|
115
116
|
}
|
package/dist/api-exports.d.ts
CHANGED
|
@@ -402,5 +402,5 @@ export declare const AI: {
|
|
|
402
402
|
generate(context: string, messages: import("./interfaces/chat.js").ChatMessage[], agentId?: string): Promise<string>;
|
|
403
403
|
};
|
|
404
404
|
export { LuaSkill, LuaTool, LuaWebhook, LuaWebhookConfig, LuaJob, LuaJobConfig, JobSchedule, PreProcessor, PreProcessorConfig, PostProcessor, PostProcessorConfig, LuaAgent, LuaAgentConfig, BasketStatus, OrderStatus, env };
|
|
405
|
-
export { JobInstance };
|
|
405
|
+
export { JobInstance, UserDataInstance, DataEntryInstance, ProductInstance, BasketInstance, OrderInstance };
|
|
406
406
|
export { ChatHistoryMessage, ChatHistoryContent, ChatMessage, TextMessage, ImageMessage, FileMessage, PreProcessorOverride, PostProcessorOverride };
|
package/dist/api-exports.js
CHANGED
|
@@ -31,6 +31,11 @@ import { BasketStatus } from "./interfaces/baskets.js";
|
|
|
31
31
|
import { OrderStatus } from "./interfaces/orders.js";
|
|
32
32
|
import { getUserInstance, getDataInstance, getProductsInstance, getBasketsInstance, getOrderInstance, getJobInstance, getChatInstance, } from "./api/lazy-instances.js";
|
|
33
33
|
import { JobInstance } from "./common/job.instance.js";
|
|
34
|
+
import ProductInstance from "./common/product.instance.js";
|
|
35
|
+
import DataEntryInstance from "./common/data.entry.instance.js";
|
|
36
|
+
import UserDataInstance from "./common/user.instance.js";
|
|
37
|
+
import BasketInstance from "./common/basket.instance.js";
|
|
38
|
+
import OrderInstance from "./common/order.instance.js";
|
|
34
39
|
export const User = {
|
|
35
40
|
/**
|
|
36
41
|
* Retrieves current user data.
|
|
@@ -543,4 +548,4 @@ export const AI = {
|
|
|
543
548
|
// Export skill classes and utilities
|
|
544
549
|
export { LuaSkill, LuaWebhook, LuaJob, PreProcessor, PostProcessor, LuaAgent, BasketStatus, OrderStatus, env };
|
|
545
550
|
// Export instance classes
|
|
546
|
-
export { JobInstance };
|
|
551
|
+
export { JobInstance, UserDataInstance, DataEntryInstance, ProductInstance, BasketInstance, OrderInstance };
|
package/dist/commands/chat.js
CHANGED
|
@@ -123,8 +123,10 @@ async function startChatLoop(chatEnv) {
|
|
|
123
123
|
console.log(`Environment: ${chatEnv.type === 'sandbox' ? '🔧 Sandbox' : '🚀 Production'}`);
|
|
124
124
|
console.log("Press Ctrl+C to exit");
|
|
125
125
|
console.log("=".repeat(60) + "\n");
|
|
126
|
-
// Welcome message
|
|
127
|
-
|
|
126
|
+
// Welcome message from config or default
|
|
127
|
+
const config = readSkillConfig();
|
|
128
|
+
const welcomeMessage = config?.agent?.welcomeMessage || "Hi there! How can I help you today?";
|
|
129
|
+
console.log(`🌙 Assistant: ${welcomeMessage}\n`);
|
|
128
130
|
// Create readline interface
|
|
129
131
|
const rl = readline.createInterface({
|
|
130
132
|
input: process.stdin,
|
|
@@ -146,28 +148,41 @@ async function startChatLoop(chatEnv) {
|
|
|
146
148
|
rl.prompt();
|
|
147
149
|
return;
|
|
148
150
|
}
|
|
151
|
+
// Start typing indicator
|
|
152
|
+
const typingInterval = startTypingIndicator();
|
|
153
|
+
let firstChunk = true;
|
|
149
154
|
try {
|
|
150
|
-
//
|
|
151
|
-
const
|
|
152
|
-
|
|
155
|
+
// Create a callback that stops typing on first chunk
|
|
156
|
+
const handleChunk = (chunk) => {
|
|
157
|
+
if (firstChunk) {
|
|
158
|
+
// Stop typing indicator and show assistant label
|
|
159
|
+
stopTypingIndicator(typingInterval);
|
|
160
|
+
process.stdout.write('🌙 Assistant: ');
|
|
161
|
+
firstChunk = false;
|
|
162
|
+
}
|
|
163
|
+
// Write the chunk immediately
|
|
164
|
+
process.stdout.write(chunk);
|
|
165
|
+
};
|
|
153
166
|
if (chatEnv.type === 'sandbox') {
|
|
154
|
-
// Send to sandbox with skill overrides
|
|
155
|
-
|
|
167
|
+
// Send to sandbox with skill overrides (streaming)
|
|
168
|
+
await sendSandboxMessageStream(chatEnv, message, handleChunk);
|
|
156
169
|
}
|
|
157
170
|
else {
|
|
158
|
-
// Send to production
|
|
159
|
-
|
|
171
|
+
// Send to production (streaming)
|
|
172
|
+
await sendProductionMessageStream(chatEnv, message, handleChunk);
|
|
160
173
|
}
|
|
161
|
-
//
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
console.log(`🌙 Assistant: ${response}\n`);
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
console.log("🌙 Assistant: ❌ Failed to get response. Please try again.\n");
|
|
174
|
+
// If no chunks arrived, stop the typing indicator
|
|
175
|
+
if (firstChunk) {
|
|
176
|
+
stopTypingIndicator(typingInterval);
|
|
168
177
|
}
|
|
178
|
+
// Add newline after response
|
|
179
|
+
console.log('\n');
|
|
169
180
|
}
|
|
170
181
|
catch (error) {
|
|
182
|
+
// Make sure typing indicator is stopped on error
|
|
183
|
+
if (firstChunk) {
|
|
184
|
+
stopTypingIndicator(typingInterval);
|
|
185
|
+
}
|
|
171
186
|
console.error(`\n❌ Error: ${error instanceof Error ? error.message : 'Unknown error'}\n`);
|
|
172
187
|
}
|
|
173
188
|
rl.prompt();
|
|
@@ -202,16 +217,16 @@ function stopTypingIndicator(interval) {
|
|
|
202
217
|
process.stdout.write('\r\x1b[K');
|
|
203
218
|
}
|
|
204
219
|
/**
|
|
205
|
-
* Sends a message to the sandbox environment with skill overrides
|
|
220
|
+
* Sends a message to the sandbox environment with skill overrides (streaming)
|
|
206
221
|
*/
|
|
207
|
-
async function
|
|
222
|
+
async function sendSandboxMessageStream(chatEnv, message, onChunk) {
|
|
208
223
|
if (!chatEnv.deployData) {
|
|
209
|
-
|
|
224
|
+
throw new Error("Sandbox environment not properly initialized.");
|
|
210
225
|
}
|
|
211
226
|
// Get all sandbox skill IDs for skill override
|
|
212
227
|
const allSkillOverrides = await getAllSandboxSkillIds(chatEnv.deployData);
|
|
213
228
|
if (allSkillOverrides.length === 0) {
|
|
214
|
-
|
|
229
|
+
throw new Error("No sandbox skills found. Please try running the command again.");
|
|
215
230
|
}
|
|
216
231
|
const chatRequest = {
|
|
217
232
|
messages: [
|
|
@@ -230,17 +245,12 @@ async function sendSandboxMessage(chatEnv, message) {
|
|
|
230
245
|
chatRequest.personaOverride = chatEnv.persona;
|
|
231
246
|
}
|
|
232
247
|
const chatApi = new ChatApi(BASE_URLS.CHAT, chatEnv.apiKey);
|
|
233
|
-
|
|
234
|
-
if (!response.success) {
|
|
235
|
-
console.error(`❌ Chat API error: ${response.error?.message || 'Unknown error'}`);
|
|
236
|
-
return null;
|
|
237
|
-
}
|
|
238
|
-
return response.data?.text || null;
|
|
248
|
+
await chatApi.sendMessageStream(chatEnv.agentId, chatRequest, onChunk);
|
|
239
249
|
}
|
|
240
250
|
/**
|
|
241
|
-
* Sends a message to the production environment
|
|
251
|
+
* Sends a message to the production environment (streaming)
|
|
242
252
|
*/
|
|
243
|
-
async function
|
|
253
|
+
async function sendProductionMessageStream(chatEnv, message, onChunk) {
|
|
244
254
|
const chatRequest = {
|
|
245
255
|
messages: [
|
|
246
256
|
{
|
|
@@ -254,10 +264,5 @@ async function sendProductionMessage(chatEnv, message) {
|
|
|
254
264
|
postprocessorOverride: []
|
|
255
265
|
};
|
|
256
266
|
const chatApi = new ChatApi(BASE_URLS.CHAT, chatEnv.apiKey);
|
|
257
|
-
|
|
258
|
-
if (!response.success) {
|
|
259
|
-
console.error(`❌ Chat API error: ${response.error?.message || 'Unknown error'}`);
|
|
260
|
-
return null;
|
|
261
|
-
}
|
|
262
|
-
return response.data?.text || null;
|
|
267
|
+
await chatApi.sendMessageStream(chatEnv.agentId, chatRequest, onChunk);
|
|
263
268
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -127,14 +127,18 @@ export async function initCommand() {
|
|
|
127
127
|
}
|
|
128
128
|
// Step 5: Initialize or update project
|
|
129
129
|
if (yamlExists) {
|
|
130
|
-
// Update existing YAML
|
|
130
|
+
// Update existing YAML and LuaAgent in index.ts
|
|
131
131
|
writeInfo("📝 Updating existing lua.skill.yaml with new agent...");
|
|
132
132
|
updateYamlAgent(selectedAgent.agentId, selectedOrg.id, persona, welcomeMessage);
|
|
133
|
+
// Also update LuaAgent in index.ts if it exists
|
|
134
|
+
const { updateLuaAgentInIndexFile } = await import("../utils/init-helpers.js");
|
|
135
|
+
updateLuaAgentInIndexFile(process.cwd(), selectedAgent.name, persona, welcomeMessage);
|
|
133
136
|
writeSuccess("✅ lua.skill.yaml updated successfully!");
|
|
137
|
+
writeSuccess("✅ LuaAgent configuration updated!");
|
|
134
138
|
}
|
|
135
139
|
else {
|
|
136
140
|
// Full project initialization
|
|
137
|
-
const currentDir = initializeProject(selectedAgent.agentId, selectedOrg.id, persona, welcomeMessage);
|
|
141
|
+
const currentDir = initializeProject(selectedAgent.agentId, selectedOrg.id, persona, welcomeMessage, selectedAgent.name);
|
|
138
142
|
// Step 6: Install dependencies
|
|
139
143
|
await installDependencies(currentDir);
|
|
140
144
|
writeSuccess("✅ Lua skill project initialized successfully!");
|
|
@@ -290,7 +294,11 @@ async function handleAgentSwitch(userData, apiKey, existingYaml) {
|
|
|
290
294
|
// Update existing YAML file with new agent
|
|
291
295
|
writeInfo("\n📝 Updating lua.skill.yaml with new agent...");
|
|
292
296
|
updateYamlAgent(selectedAgent.agentId, selectedOrg.id, finalPersona, finalWelcomeMessage);
|
|
297
|
+
// Also update LuaAgent in index.ts if it exists
|
|
298
|
+
const { updateLuaAgentInIndexFile } = await import("../utils/init-helpers.js");
|
|
299
|
+
updateLuaAgentInIndexFile(process.cwd(), selectedAgent.name, finalPersona, finalWelcomeMessage);
|
|
293
300
|
writeSuccess("✅ lua.skill.yaml updated successfully!");
|
|
301
|
+
writeSuccess("✅ LuaAgent configuration updated!");
|
|
294
302
|
writeInfo("\n💡 Your project now uses the new agent. Run 'lua compile' to update your skills.\n");
|
|
295
303
|
}
|
|
296
304
|
/**
|
package/dist/index.js
CHANGED
|
@@ -16,10 +16,10 @@ const program = new Command();
|
|
|
16
16
|
program
|
|
17
17
|
.name("lua")
|
|
18
18
|
.description("Lua AI - Build and deploy AI agents with superpowers")
|
|
19
|
-
.version("2.
|
|
19
|
+
.version("2.5.8")
|
|
20
20
|
.addHelpText('before', `
|
|
21
21
|
------------------------------------------------------------------
|
|
22
|
-
Lua AI CLI v2.
|
|
22
|
+
Lua AI CLI v2.5.8 - Build and deploy AI agents with superpowers
|
|
23
23
|
------------------------------------------------------------------
|
|
24
24
|
`)
|
|
25
25
|
.addHelpText('after', `
|
|
@@ -5,12 +5,12 @@ export type TextMessage = {
|
|
|
5
5
|
export type ImageMessage = {
|
|
6
6
|
type: "image";
|
|
7
7
|
image: string;
|
|
8
|
-
|
|
8
|
+
mediaType: string;
|
|
9
9
|
};
|
|
10
10
|
export type FileMessage = {
|
|
11
11
|
type: "file";
|
|
12
12
|
data: string;
|
|
13
|
-
|
|
13
|
+
mediaType: string;
|
|
14
14
|
};
|
|
15
15
|
export type Message = TextMessage | ImageMessage | FileMessage;
|
|
16
16
|
export interface SendMessageRequest {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Handles LuaAgent persona and welcome message synchronization with lua.skill.yaml
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
* Syncs the agent's persona and welcome message with lua.skill.yaml.
|
|
6
|
+
* Syncs the agent's name, persona, and welcome message with lua.skill.yaml.
|
|
7
7
|
* This ensures the YAML configuration reflects the agent definition in code.
|
|
8
8
|
*
|
|
9
9
|
* @param agentMetadata - Agent metadata extracted from LuaAgent
|
|
@@ -7,7 +7,7 @@ import path from "path";
|
|
|
7
7
|
import yaml from "js-yaml";
|
|
8
8
|
import { COMPILE_FILES, YAML_FORMAT } from '../config/compile.constants.js';
|
|
9
9
|
/**
|
|
10
|
-
* Syncs the agent's persona and welcome message with lua.skill.yaml.
|
|
10
|
+
* Syncs the agent's name, persona, and welcome message with lua.skill.yaml.
|
|
11
11
|
* This ensures the YAML configuration reflects the agent definition in code.
|
|
12
12
|
*
|
|
13
13
|
* @param agentMetadata - Agent metadata extracted from LuaAgent
|
|
@@ -20,12 +20,14 @@ export async function syncAgentPersonaWithYaml(agentMetadata) {
|
|
|
20
20
|
const yamlContent = fs.readFileSync(yamlPath, 'utf8');
|
|
21
21
|
config = yaml.load(yamlContent);
|
|
22
22
|
}
|
|
23
|
-
// Update agent section with persona and welcome message
|
|
23
|
+
// Update agent section with name, persona, and welcome message
|
|
24
24
|
config.agent = {
|
|
25
25
|
...config.agent,
|
|
26
26
|
persona: agentMetadata.persona,
|
|
27
27
|
welcomeMessage: agentMetadata.welcomeMessage
|
|
28
28
|
};
|
|
29
|
+
// Store agent name as a comment or in metadata (YAML doesn't have an agentName field)
|
|
30
|
+
// The agent name is primarily for the LuaAgent in code
|
|
29
31
|
// Write updated YAML with consistent formatting
|
|
30
32
|
const yamlContent = yaml.dump(config, {
|
|
31
33
|
indent: YAML_FORMAT.INDENT,
|
|
@@ -37,7 +39,7 @@ export async function syncAgentPersonaWithYaml(agentMetadata) {
|
|
|
37
39
|
}
|
|
38
40
|
});
|
|
39
41
|
fs.writeFileSync(yamlPath, yamlContent);
|
|
40
|
-
console.log(`✅ Synced agent
|
|
42
|
+
console.log(`✅ Synced agent configuration to lua.skill.yaml`);
|
|
41
43
|
}
|
|
42
44
|
/**
|
|
43
45
|
* Reads the agent persona from lua.skill.yaml.
|
|
@@ -17,7 +17,7 @@ export declare function getTemplateDir(): string;
|
|
|
17
17
|
* @param welcomeMessage - Optional welcome message
|
|
18
18
|
* @returns Current working directory
|
|
19
19
|
*/
|
|
20
|
-
export declare function initializeProject(agentId: string, orgId: string, persona?: string, welcomeMessage?: string): string;
|
|
20
|
+
export declare function initializeProject(agentId: string, orgId: string, persona?: string, welcomeMessage?: string, agentName?: string): string;
|
|
21
21
|
/**
|
|
22
22
|
* Installs npm dependencies for the project.
|
|
23
23
|
*
|
|
@@ -39,3 +39,12 @@ export declare function calculatePromptLines(baseCount: number, additionalLines:
|
|
|
39
39
|
* @param lineCount - Number of lines to clear
|
|
40
40
|
*/
|
|
41
41
|
export declare function clearLinesIfNeeded(lineCount: number): void;
|
|
42
|
+
/**
|
|
43
|
+
* Updates the LuaAgent configuration in the template's index.ts file
|
|
44
|
+
*
|
|
45
|
+
* @param projectDir - Project directory containing src/index.ts
|
|
46
|
+
* @param agentName - Name of the agent
|
|
47
|
+
* @param persona - Agent persona
|
|
48
|
+
* @param welcomeMessage - Welcome message
|
|
49
|
+
*/
|
|
50
|
+
export declare function updateLuaAgentInIndexFile(projectDir: string, agentName?: string, persona?: string, welcomeMessage?: string): void;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
import path from "path";
|
|
7
|
+
import fs from "fs";
|
|
7
8
|
import { copyTemplateFiles, createSkillYaml } from "./files.js";
|
|
8
9
|
import { clearPromptLines, writeProgress } from "./cli.js";
|
|
9
10
|
import { execSync } from 'child_process';
|
|
@@ -26,13 +27,16 @@ export function getTemplateDir() {
|
|
|
26
27
|
* @param welcomeMessage - Optional welcome message
|
|
27
28
|
* @returns Current working directory
|
|
28
29
|
*/
|
|
29
|
-
export function initializeProject(agentId, orgId, persona, welcomeMessage) {
|
|
30
|
+
export function initializeProject(agentId, orgId, persona, welcomeMessage, agentName) {
|
|
30
31
|
const templateDir = getTemplateDir();
|
|
31
32
|
const currentDir = process.cwd();
|
|
32
33
|
copyTemplateFiles(templateDir, currentDir);
|
|
33
34
|
createSkillYaml(agentId, orgId, undefined, undefined, persona, welcomeMessage);
|
|
35
|
+
// Update LuaAgent in index.ts with agent configuration
|
|
36
|
+
updateLuaAgentInIndexFile(currentDir, agentName, persona, welcomeMessage);
|
|
34
37
|
writeProgress("✅ Created lua.skill.yaml");
|
|
35
38
|
writeProgress("✅ Copied template files");
|
|
39
|
+
writeProgress("✅ Updated LuaAgent configuration");
|
|
36
40
|
return currentDir;
|
|
37
41
|
}
|
|
38
42
|
/**
|
|
@@ -71,3 +75,42 @@ export function clearLinesIfNeeded(lineCount) {
|
|
|
71
75
|
clearPromptLines(lineCount);
|
|
72
76
|
}
|
|
73
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Updates the LuaAgent configuration in the template's index.ts file
|
|
80
|
+
*
|
|
81
|
+
* @param projectDir - Project directory containing src/index.ts
|
|
82
|
+
* @param agentName - Name of the agent
|
|
83
|
+
* @param persona - Agent persona
|
|
84
|
+
* @param welcomeMessage - Welcome message
|
|
85
|
+
*/
|
|
86
|
+
export function updateLuaAgentInIndexFile(projectDir, agentName, persona, welcomeMessage) {
|
|
87
|
+
const indexPath = path.join(projectDir, 'src', 'index.ts');
|
|
88
|
+
if (!fs.existsSync(indexPath)) {
|
|
89
|
+
// If no index.ts, skip (might be an old template structure)
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
let content = fs.readFileSync(indexPath, 'utf8');
|
|
94
|
+
// Check if LuaAgent exists in the file
|
|
95
|
+
if (!content.includes('new LuaAgent(')) {
|
|
96
|
+
return; // No LuaAgent to update
|
|
97
|
+
}
|
|
98
|
+
// Update agent name
|
|
99
|
+
if (agentName) {
|
|
100
|
+
content = content.replace(/name:\s*['"][^'"]*['"]/, `name: '${agentName.replace(/'/g, "\\'")}'`);
|
|
101
|
+
}
|
|
102
|
+
// Update persona
|
|
103
|
+
if (persona) {
|
|
104
|
+
content = content.replace(/(persona:\s*['"`])[\s\S]*?(['"`])/, `$1${persona.replace(/'/g, "\\'").replace(/`/g, '\\`')}$2`);
|
|
105
|
+
}
|
|
106
|
+
// Update welcome message
|
|
107
|
+
if (welcomeMessage) {
|
|
108
|
+
content = content.replace(/(welcomeMessage:\s*['"])[\s\S]*?(['"])/, `$1${welcomeMessage.replace(/'/g, "\\'")}$2`);
|
|
109
|
+
}
|
|
110
|
+
fs.writeFileSync(indexPath, content);
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
// Silently fail - not critical
|
|
114
|
+
console.warn('Warning: Could not update LuaAgent in index.ts');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -40,7 +40,7 @@ export async function preBundleJobsInSource(sourceFilePath, project, distDir) {
|
|
|
40
40
|
if (object.getText() === 'Jobs' && property === 'create') {
|
|
41
41
|
jobIndex++;
|
|
42
42
|
const placeholder = `${JOB_PLACEHOLDER}_${jobIndex}`;
|
|
43
|
-
console.log(`[PreBundleJobs] Found Jobs.create() #${jobIndex}`);
|
|
43
|
+
// console.log(`[PreBundleJobs] Found Jobs.create() #${jobIndex}`);
|
|
44
44
|
// Get the config object argument
|
|
45
45
|
const args = node.getArguments();
|
|
46
46
|
if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
|
|
@@ -51,12 +51,12 @@ export async function preBundleJobsInSource(sourceFilePath, project, distDir) {
|
|
|
51
51
|
const executeInitializer = executeProperty.getInitializer();
|
|
52
52
|
if (executeInitializer) {
|
|
53
53
|
const executeCode = executeInitializer.getText();
|
|
54
|
-
console.log(`[PreBundleJobs] Extracting execute function for bundling...`);
|
|
54
|
+
// console.log(`[PreBundleJobs] Extracting execute function for bundling...`);
|
|
55
55
|
// Bundle the execute function with dependencies (async)
|
|
56
56
|
const bundlePromise = bundleJobExecuteFunction(executeCode, `job_${jobIndex}`, distDir, sourceFilePath).then(bundledCode => {
|
|
57
57
|
if (bundledCode) {
|
|
58
58
|
jobBundles.set(placeholder, bundledCode);
|
|
59
|
-
console.log(`[PreBundleJobs] ✅ Bundled job #${jobIndex} with dependencies`);
|
|
59
|
+
// console.log(`[PreBundleJobs] ✅ Bundled job #${jobIndex} with dependencies`);
|
|
60
60
|
}
|
|
61
61
|
});
|
|
62
62
|
bundlingPromises.push(bundlePromise);
|
|
@@ -74,9 +74,9 @@ export async function preBundleJobsInSource(sourceFilePath, project, distDir) {
|
|
|
74
74
|
});
|
|
75
75
|
// Wait for all bundling to complete
|
|
76
76
|
if (bundlingPromises.length > 0) {
|
|
77
|
-
console.log(`[PreBundleJobs] Waiting for ${bundlingPromises.length} job(s) to bundle...`);
|
|
77
|
+
// console.log(`[PreBundleJobs] Waiting for ${bundlingPromises.length} job(s) to bundle...`);
|
|
78
78
|
await Promise.all(bundlingPromises);
|
|
79
|
-
console.log(`[PreBundleJobs] ✅ All job bundles complete`);
|
|
79
|
+
// console.log(`[PreBundleJobs] ✅ All job bundles complete`);
|
|
80
80
|
}
|
|
81
81
|
return { modifiedSource, jobBundles };
|
|
82
82
|
}
|
|
@@ -103,7 +103,7 @@ async function bundleJobExecuteFunction(executeCode, jobName, distDir, sourceFil
|
|
|
103
103
|
!imp.includes('api-exports') && // Exclude api-exports
|
|
104
104
|
!imp.includes('../../../dist/api-exports') // Exclude direct api-exports imports
|
|
105
105
|
);
|
|
106
|
-
console.log(`[PreBundleJobs] Including ${relevantImports.length} import(s) in job bundle`);
|
|
106
|
+
// console.log(`[PreBundleJobs] Including ${relevantImports.length} import(s) in job bundle`);
|
|
107
107
|
// Create a TypeScript module with the execute function and all imports
|
|
108
108
|
const moduleCode = `
|
|
109
109
|
// Auto-generated job execute bundle
|
|
@@ -133,7 +133,7 @@ export default executeFunc;
|
|
|
133
133
|
});
|
|
134
134
|
// Read bundled code
|
|
135
135
|
const bundledCode = fs.readFileSync(tempOutput, 'utf8');
|
|
136
|
-
console.log(`[PreBundleJobs] Bundle size: ${(bundledCode.length / 1024).toFixed(2)}KB`);
|
|
136
|
+
// console.log(`[PreBundleJobs] Bundle size: ${(bundledCode.length / 1024).toFixed(2)}KB`);
|
|
137
137
|
// DON'T compress - just wrap for VM execution
|
|
138
138
|
// Compression happens later when the entire tool is bundled
|
|
139
139
|
const wrappedCode = `(async (job) => {
|
|
@@ -150,7 +150,7 @@ export default executeFunc;
|
|
|
150
150
|
return wrappedCode;
|
|
151
151
|
}
|
|
152
152
|
catch (error) {
|
|
153
|
-
console.warn(`[PreBundleJobs] Error bundling job ${jobName}:`, error);
|
|
153
|
+
// console.warn(`[PreBundleJobs] Error bundling job ${jobName}:`, error);
|
|
154
154
|
try {
|
|
155
155
|
if (fs.existsSync(tempOutput))
|
|
156
156
|
fs.unlinkSync(tempOutput);
|
|
@@ -170,7 +170,7 @@ export function replaceJobPlaceholders(bundledCode, jobBundles) {
|
|
|
170
170
|
// It appears as: execute: __BUNDLED_JOB_EXECUTE___1
|
|
171
171
|
const placeholderPattern = new RegExp(placeholder, 'g');
|
|
172
172
|
result = result.replace(placeholderPattern, bundledJobCode);
|
|
173
|
-
console.log(`[PreBundleJobs] ✅ Replaced ${placeholder} with bundled code (${(bundledJobCode.length / 1024).toFixed(1)}KB)`);
|
|
173
|
+
// console.log(`[PreBundleJobs] ✅ Replaced ${placeholder} with bundled code (${(bundledJobCode.length / 1024).toFixed(1)}KB)`);
|
|
174
174
|
});
|
|
175
175
|
return result;
|
|
176
176
|
}
|
package/dist/utils/sandbox.js
CHANGED
|
@@ -231,10 +231,9 @@ export function createSandbox(options) {
|
|
|
231
231
|
const executeString = typeof config.execute === 'function'
|
|
232
232
|
? config.execute.toString()
|
|
233
233
|
: config.execute;
|
|
234
|
-
console.log('IsDynamicJob', config.dynamic);
|
|
235
234
|
// Create job with version and activation
|
|
236
235
|
return await jobService.createJobInstance({
|
|
237
|
-
name: config.name,
|
|
236
|
+
name: config.name + '_' + Date.now(),
|
|
238
237
|
description: config.description,
|
|
239
238
|
context: config.description || '',
|
|
240
239
|
schedule: config.schedule,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lua-cli",
|
|
3
|
-
"version": "3.0.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Build, test, and deploy AI agents with custom tools, webhooks, and scheduled jobs. Features LuaAgent unified configuration, streaming chat, and batch deployment.",
|
|
5
5
|
"readmeFilename": "README.md",
|
|
6
6
|
"main": "dist/api-exports.js",
|
|
7
7
|
"bin": {
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"inquirer": "^12.9.6",
|
|
73
73
|
"js-yaml": "^4.1.0",
|
|
74
74
|
"keytar": "^7.9.0",
|
|
75
|
-
"lua-ai-chat": "^0.0.
|
|
75
|
+
"lua-ai-chat": "^0.0.6",
|
|
76
76
|
"lua-cli": "^2.3.0-alpha.1",
|
|
77
77
|
"luaniverse": "^4.0.43",
|
|
78
78
|
"node-fetch": "^3.3.2",
|