lua-cli 3.17.4 → 3.18.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/dist/api-exports.d.ts +401 -13
- package/dist/api-exports.js +626 -405
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +2312 -599
- package/dist/index.js.map +1 -1
- package/dist/voice/test/index.d.ts +28 -7
- package/dist/zod-runtime.mjs +2 -2
- package/docs/API_REFERENCE.md +48 -1
- package/docs/README.md +1 -1
- package/docs/api/Templates.md +21 -3
- package/package.json +2 -2
- package/template/package.json +1 -1
package/dist/api-exports.js
CHANGED
|
@@ -9,403 +9,6 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
// src/interfaces/baskets.ts
|
|
13
|
-
var BasketStatus;
|
|
14
|
-
var init_baskets = __esm({
|
|
15
|
-
"src/interfaces/baskets.ts"() {
|
|
16
|
-
"use strict";
|
|
17
|
-
BasketStatus = /* @__PURE__ */ (function(BasketStatus2) {
|
|
18
|
-
BasketStatus2["ACTIVE"] = "active";
|
|
19
|
-
BasketStatus2["CHECKED_OUT"] = "checked_out";
|
|
20
|
-
BasketStatus2["ABANDONED"] = "abandoned";
|
|
21
|
-
BasketStatus2["EXPIRED"] = "expired";
|
|
22
|
-
return BasketStatus2;
|
|
23
|
-
})({});
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// src/config/constants.ts
|
|
28
|
-
import { join } from "path";
|
|
29
|
-
import { homedir } from "os";
|
|
30
|
-
var CLI_CONFIG_DIR, VERSION_CHECK_FILE, TELEMETRY_FILE, CLI_CACHE_FILE, BASE_URLS, CREDENTIALS_FILE, SANDBOX_STORAGE_FILE, AUTH_STORAGE_FILE;
|
|
31
|
-
var init_constants = __esm({
|
|
32
|
-
"src/config/constants.ts"() {
|
|
33
|
-
"use strict";
|
|
34
|
-
CLI_CONFIG_DIR = join(homedir(), ".lua-cli");
|
|
35
|
-
VERSION_CHECK_FILE = join(CLI_CONFIG_DIR, "version-check.json");
|
|
36
|
-
TELEMETRY_FILE = join(CLI_CONFIG_DIR, "telemetry.json");
|
|
37
|
-
CLI_CACHE_FILE = join(CLI_CONFIG_DIR, "cache.json");
|
|
38
|
-
BASE_URLS = {
|
|
39
|
-
API: process.env.LUA_API_URL || "https://api.heylua.ai",
|
|
40
|
-
AUTH: process.env.LUA_AUTH_URL || "https://auth.heylua.ai",
|
|
41
|
-
CHAT: process.env.LUA_API_URL || "https://api.heylua.ai",
|
|
42
|
-
WEBHOOK: "https://webhook.heylua.ai",
|
|
43
|
-
CDN: "https://cdn.heylua.ai"
|
|
44
|
-
};
|
|
45
|
-
CREDENTIALS_FILE = join(CLI_CONFIG_DIR, "credentials");
|
|
46
|
-
SANDBOX_STORAGE_FILE = join(CLI_CONFIG_DIR, "sandbox.json");
|
|
47
|
-
AUTH_STORAGE_FILE = join(CLI_CONFIG_DIR, "auth.json");
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// src/errors/auth.error.ts
|
|
52
|
-
var AuthenticationError;
|
|
53
|
-
var init_auth_error = __esm({
|
|
54
|
-
"src/errors/auth.error.ts"() {
|
|
55
|
-
"use strict";
|
|
56
|
-
AuthenticationError = class _AuthenticationError extends Error {
|
|
57
|
-
static {
|
|
58
|
-
__name(this, "AuthenticationError");
|
|
59
|
-
}
|
|
60
|
-
statusCode = 401;
|
|
61
|
-
isAuthenticationError = true;
|
|
62
|
-
reason;
|
|
63
|
-
serverMessage;
|
|
64
|
-
/**
|
|
65
|
-
* If true, the error message already contains complete remediation steps
|
|
66
|
-
* and `withErrorHandling` should not append its own hint block. Use this
|
|
67
|
-
* when the throw site has more context about the right fix than the
|
|
68
|
-
* generic per-reason hints (e.g. `getToken()` listing all three ways to
|
|
69
|
-
* configure a key — keychain, env var, .env file).
|
|
70
|
-
*/
|
|
71
|
-
suppressDefaultRemediation;
|
|
72
|
-
constructor(message = "Invalid API key", reason = "unknown", serverMessage, suppressDefaultRemediation = false) {
|
|
73
|
-
super(message);
|
|
74
|
-
this.name = "AuthenticationError";
|
|
75
|
-
this.reason = reason;
|
|
76
|
-
this.serverMessage = serverMessage;
|
|
77
|
-
this.suppressDefaultRemediation = suppressDefaultRemediation;
|
|
78
|
-
if (Error.captureStackTrace) {
|
|
79
|
-
Error.captureStackTrace(this, _AuthenticationError);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Checks if an error is an AuthenticationError
|
|
84
|
-
* @param error - The error to check
|
|
85
|
-
* @returns True if the error is an AuthenticationError
|
|
86
|
-
*/
|
|
87
|
-
static isAuthenticationError(error) {
|
|
88
|
-
return error instanceof _AuthenticationError || error instanceof Error && "isAuthenticationError" in error && error.isAuthenticationError === true;
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
// src/api/http.client.ts
|
|
95
|
-
import { randomUUID } from "crypto";
|
|
96
|
-
var HttpClient;
|
|
97
|
-
var init_http_client = __esm({
|
|
98
|
-
"src/api/http.client.ts"() {
|
|
99
|
-
"use strict";
|
|
100
|
-
init_auth_error();
|
|
101
|
-
HttpClient = class {
|
|
102
|
-
static {
|
|
103
|
-
__name(this, "HttpClient");
|
|
104
|
-
}
|
|
105
|
-
baseUrl;
|
|
106
|
-
/**
|
|
107
|
-
* Creates an instance of HttpClient
|
|
108
|
-
* @param baseUrl - The base URL for all API requests
|
|
109
|
-
*/
|
|
110
|
-
constructor(baseUrl) {
|
|
111
|
-
this.baseUrl = baseUrl;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Makes an HTTP request with standardized error handling
|
|
115
|
-
* @param url - The full URL to request
|
|
116
|
-
* @param options - Fetch API request options
|
|
117
|
-
* @returns Promise resolving to an ApiResponse with typed data
|
|
118
|
-
* @private
|
|
119
|
-
*/
|
|
120
|
-
async request(url, options = {}) {
|
|
121
|
-
const controller = new AbortController();
|
|
122
|
-
const timeoutId = setTimeout(() => controller.abort(), 3e4);
|
|
123
|
-
try {
|
|
124
|
-
const response = await fetch(url, {
|
|
125
|
-
...options,
|
|
126
|
-
signal: controller.signal,
|
|
127
|
-
headers: {
|
|
128
|
-
"Content-Type": "application/json",
|
|
129
|
-
...options.headers
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
clearTimeout(timeoutId);
|
|
133
|
-
if (!response.ok) {
|
|
134
|
-
let errorData;
|
|
135
|
-
try {
|
|
136
|
-
errorData = await response.json();
|
|
137
|
-
} catch (jsonError) {
|
|
138
|
-
errorData = {};
|
|
139
|
-
}
|
|
140
|
-
if (response.status === 401) {
|
|
141
|
-
const serverMessage = typeof errorData.message === "string" ? errorData.message : void 0;
|
|
142
|
-
if (serverMessage && /not an admin/i.test(serverMessage)) {
|
|
143
|
-
throw new AuthenticationError(`Access denied for this agent: ${serverMessage}`, "no_agent_access", serverMessage);
|
|
144
|
-
}
|
|
145
|
-
const isExplicitCredential = !!serverMessage && /(invalid|expired|missing|no)\s+(api[\s_-]?key|token|credential)/i.test(serverMessage);
|
|
146
|
-
const isBareAuthRejection = !serverMessage || /^unauthorized$/i.test(serverMessage);
|
|
147
|
-
if (isExplicitCredential || isBareAuthRejection) {
|
|
148
|
-
throw new AuthenticationError("Authentication failed. Your API key may be invalid or expired.", "invalid_credentials", serverMessage);
|
|
149
|
-
}
|
|
150
|
-
throw new AuthenticationError(`Authentication failed: ${serverMessage}`, "unknown", serverMessage);
|
|
151
|
-
}
|
|
152
|
-
if (response.status === 403) {
|
|
153
|
-
const detail = errorData.message || "You do not have permission to access this resource.";
|
|
154
|
-
throw new Error(`Access denied (403): ${detail}
|
|
155
|
-
Check that your API key has access to this agent/organization.`);
|
|
156
|
-
}
|
|
157
|
-
return {
|
|
158
|
-
success: false,
|
|
159
|
-
error: {
|
|
160
|
-
message: errorData.message || `HTTP ${response.status}: ${response.statusText}`,
|
|
161
|
-
statusCode: response.status,
|
|
162
|
-
error: errorData.error,
|
|
163
|
-
...errorData
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
let data;
|
|
168
|
-
try {
|
|
169
|
-
data = await response.json();
|
|
170
|
-
} catch (jsonError) {
|
|
171
|
-
data = {};
|
|
172
|
-
}
|
|
173
|
-
if (typeof data === "object" && data !== null && "success" in data) {
|
|
174
|
-
return data;
|
|
175
|
-
}
|
|
176
|
-
return {
|
|
177
|
-
success: true,
|
|
178
|
-
data
|
|
179
|
-
};
|
|
180
|
-
} catch (error) {
|
|
181
|
-
clearTimeout(timeoutId);
|
|
182
|
-
if (AuthenticationError.isAuthenticationError(error)) {
|
|
183
|
-
throw error;
|
|
184
|
-
}
|
|
185
|
-
if (error instanceof Error && error.message.startsWith("Access denied (403)")) {
|
|
186
|
-
throw error;
|
|
187
|
-
}
|
|
188
|
-
if (error instanceof DOMException && error.name === "AbortError") {
|
|
189
|
-
return {
|
|
190
|
-
success: false,
|
|
191
|
-
error: {
|
|
192
|
-
message: "Request timeout (30s)",
|
|
193
|
-
statusCode: 0
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
return {
|
|
198
|
-
success: false,
|
|
199
|
-
error: {
|
|
200
|
-
message: error instanceof Error ? error.message : "Network request failed",
|
|
201
|
-
statusCode: 0
|
|
202
|
-
}
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Checks if an HTTP status code is retryable
|
|
208
|
-
* @param statusCode - The HTTP status code (0 for network errors)
|
|
209
|
-
* @returns True if the request should be retried
|
|
210
|
-
* @private
|
|
211
|
-
*/
|
|
212
|
-
isRetryableStatus(statusCode) {
|
|
213
|
-
return statusCode === 0 || statusCode === 429 || statusCode >= 500 && statusCode <= 504;
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* Calculates exponential backoff with full jitter (AWS best practice)
|
|
217
|
-
* @param attempt - The retry attempt number (0-based)
|
|
218
|
-
* @param baseMs - Base delay in milliseconds
|
|
219
|
-
* @param maxMs - Maximum delay cap in milliseconds
|
|
220
|
-
* @returns Delay in milliseconds with random jitter
|
|
221
|
-
* @private
|
|
222
|
-
*/
|
|
223
|
-
calculateBackoff(attempt, baseMs = 1e3, maxMs = 15e3) {
|
|
224
|
-
const exponential = Math.min(maxMs, baseMs * Math.pow(2, attempt));
|
|
225
|
-
return Math.max(100, Math.random() * exponential);
|
|
226
|
-
}
|
|
227
|
-
/**
|
|
228
|
-
* Wraps request with retry logic for transient failures
|
|
229
|
-
* @param url - The full URL to request
|
|
230
|
-
* @param options - Fetch API request options
|
|
231
|
-
* @param maxRetries - Maximum number of retry attempts (default 3)
|
|
232
|
-
* @returns Promise resolving to an ApiResponse with typed data
|
|
233
|
-
* @private
|
|
234
|
-
*/
|
|
235
|
-
async retryableRequest(url, options = {}, maxRetries = 3) {
|
|
236
|
-
if (options.method === "POST") {
|
|
237
|
-
const headers = options.headers || {};
|
|
238
|
-
if (!headers["X-Idempotency-Key"]) {
|
|
239
|
-
headers["X-Idempotency-Key"] = randomUUID();
|
|
240
|
-
options = {
|
|
241
|
-
...options,
|
|
242
|
-
headers: {
|
|
243
|
-
...options.headers,
|
|
244
|
-
...headers
|
|
245
|
-
}
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
let lastResult = null;
|
|
250
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
251
|
-
try {
|
|
252
|
-
const result = await this.request(url, options);
|
|
253
|
-
if (result.success || !result.error || !this.isRetryableStatus(result.error.statusCode || 0)) {
|
|
254
|
-
return result;
|
|
255
|
-
}
|
|
256
|
-
lastResult = result;
|
|
257
|
-
} catch (error) {
|
|
258
|
-
throw error;
|
|
259
|
-
}
|
|
260
|
-
if (attempt < maxRetries) {
|
|
261
|
-
const backoff = this.calculateBackoff(attempt);
|
|
262
|
-
await new Promise((resolve) => setTimeout(resolve, backoff));
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
return lastResult;
|
|
266
|
-
}
|
|
267
|
-
/**
|
|
268
|
-
* Performs an HTTP GET request
|
|
269
|
-
* @param url - The relative URL path to request (will be appended to baseUrl)
|
|
270
|
-
* @param headers - Optional HTTP headers to include in the request
|
|
271
|
-
* @returns Promise resolving to an ApiResponse with typed data
|
|
272
|
-
* @protected
|
|
273
|
-
*/
|
|
274
|
-
async httpGet(url, headers) {
|
|
275
|
-
return this.retryableRequest(this.baseUrl + url, {
|
|
276
|
-
method: "GET",
|
|
277
|
-
headers
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* Performs an HTTP POST request
|
|
282
|
-
* @param url - The relative URL path to request (will be appended to baseUrl)
|
|
283
|
-
* @param data - Optional request body data (will be JSON stringified)
|
|
284
|
-
* @param headers - Optional HTTP headers to include in the request
|
|
285
|
-
* @returns Promise resolving to an ApiResponse with typed data
|
|
286
|
-
* @protected
|
|
287
|
-
*/
|
|
288
|
-
async httpPost(url, data, headers) {
|
|
289
|
-
return this.retryableRequest(this.baseUrl + url, {
|
|
290
|
-
method: "POST",
|
|
291
|
-
body: data ? JSON.stringify(data) : void 0,
|
|
292
|
-
headers
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Performs an HTTP PUT request
|
|
297
|
-
* @param url - The relative URL path to request (will be appended to baseUrl)
|
|
298
|
-
* @param data - Optional request body data (will be JSON stringified)
|
|
299
|
-
* @param headers - Optional HTTP headers to include in the request
|
|
300
|
-
* @returns Promise resolving to an ApiResponse with typed data
|
|
301
|
-
* @protected
|
|
302
|
-
*/
|
|
303
|
-
async httpPut(url, data, headers) {
|
|
304
|
-
return this.retryableRequest(this.baseUrl + url, {
|
|
305
|
-
method: "PUT",
|
|
306
|
-
body: data ? JSON.stringify(data) : void 0,
|
|
307
|
-
headers
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* Performs an HTTP DELETE request
|
|
312
|
-
* @param url - The relative URL path to request (will be appended to baseUrl)
|
|
313
|
-
* @param headers - Optional HTTP headers to include in the request
|
|
314
|
-
* @returns Promise resolving to an ApiResponse with typed data
|
|
315
|
-
* @protected
|
|
316
|
-
*/
|
|
317
|
-
async httpDelete(url, headers) {
|
|
318
|
-
return this.retryableRequest(this.baseUrl + url, {
|
|
319
|
-
method: "DELETE",
|
|
320
|
-
headers
|
|
321
|
-
});
|
|
322
|
-
}
|
|
323
|
-
/**
|
|
324
|
-
* Performs an HTTP PATCH request
|
|
325
|
-
* @param url - The relative URL path to request (will be appended to baseUrl)
|
|
326
|
-
* @param data - Optional request body data (will be JSON stringified)
|
|
327
|
-
* @param headers - Optional HTTP headers to include in the request
|
|
328
|
-
* @returns Promise resolving to an ApiResponse with typed data
|
|
329
|
-
* @protected
|
|
330
|
-
*/
|
|
331
|
-
async httpPatch(url, data, headers) {
|
|
332
|
-
return this.retryableRequest(this.baseUrl + url, {
|
|
333
|
-
method: "PATCH",
|
|
334
|
-
body: data ? JSON.stringify(data) : void 0,
|
|
335
|
-
headers
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
// src/api/auth.api.service.ts
|
|
343
|
-
var init_auth_api_service = __esm({
|
|
344
|
-
"src/api/auth.api.service.ts"() {
|
|
345
|
-
"use strict";
|
|
346
|
-
init_http_client();
|
|
347
|
-
}
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
// src/services/auth.ts
|
|
351
|
-
import "dotenv/config";
|
|
352
|
-
import { readFileSync, writeFileSync, mkdirSync, unlinkSync } from "fs";
|
|
353
|
-
function getToken() {
|
|
354
|
-
if (process.env.LUA_API_KEY) {
|
|
355
|
-
return process.env.LUA_API_KEY;
|
|
356
|
-
}
|
|
357
|
-
try {
|
|
358
|
-
const token = readFileSync(CREDENTIALS_FILE, "utf8").trim();
|
|
359
|
-
if (token) return token;
|
|
360
|
-
} catch {
|
|
361
|
-
}
|
|
362
|
-
throw new AuthenticationError('No API key found.\n\n Authenticate using one of these methods:\n\n \u279C lua auth configure\n \u279C export LUA_API_KEY="your-api-key-here"\n \u279C Add LUA_API_KEY=... to a .env file\n\n \u{1F511} Get your API key at https://admin.heylua.ai', "invalid_credentials", void 0, true);
|
|
363
|
-
}
|
|
364
|
-
var init_auth = __esm({
|
|
365
|
-
"src/services/auth.ts"() {
|
|
366
|
-
"use strict";
|
|
367
|
-
init_auth_api_service();
|
|
368
|
-
init_constants();
|
|
369
|
-
init_auth_error();
|
|
370
|
-
__name(getToken, "getToken");
|
|
371
|
-
}
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
// src/config/compile.constants.ts
|
|
375
|
-
var COMPILE_DIRS, COMPILE_FILES, SKILL_DEFAULTS, YAML_FORMAT;
|
|
376
|
-
var init_compile_constants = __esm({
|
|
377
|
-
"src/config/compile.constants.ts"() {
|
|
378
|
-
"use strict";
|
|
379
|
-
COMPILE_DIRS = {
|
|
380
|
-
DIST: "dist",
|
|
381
|
-
DIST_V2: "dist-v2",
|
|
382
|
-
LUA: ".lua",
|
|
383
|
-
TOOLS: "tools"
|
|
384
|
-
};
|
|
385
|
-
COMPILE_FILES = {
|
|
386
|
-
DEPLOYMENT_JSON: "deployment.json",
|
|
387
|
-
DEPLOY_JSON: "deploy.json",
|
|
388
|
-
MANIFEST_JSON: "manifest.json",
|
|
389
|
-
INDEX_TS: "index.ts",
|
|
390
|
-
INDEX_JS: "index.js",
|
|
391
|
-
PACKAGE_JSON: "package.json",
|
|
392
|
-
TSCONFIG_JSON: "tsconfig.json",
|
|
393
|
-
LUA_SKILL_YAML: "lua.skill.yaml"
|
|
394
|
-
};
|
|
395
|
-
SKILL_DEFAULTS = {
|
|
396
|
-
NAME: "lua-skill",
|
|
397
|
-
VERSION: "1.0.0",
|
|
398
|
-
DESCRIPTION: "",
|
|
399
|
-
CONTEXT: ""
|
|
400
|
-
};
|
|
401
|
-
YAML_FORMAT = {
|
|
402
|
-
INDENT: 2,
|
|
403
|
-
LINE_WIDTH: -1,
|
|
404
|
-
NO_REFS: true
|
|
405
|
-
};
|
|
406
|
-
}
|
|
407
|
-
});
|
|
408
|
-
|
|
409
12
|
// ../shared-types/dist/index.mjs
|
|
410
13
|
import { z } from "zod";
|
|
411
14
|
function isPersonaTextObject(value) {
|
|
@@ -470,6 +73,14 @@ function aiGenerateInputFromSimplified(prompt, content) {
|
|
|
470
73
|
]
|
|
471
74
|
};
|
|
472
75
|
}
|
|
76
|
+
function isInteractiveChannel(channel) {
|
|
77
|
+
if (!channel) return true;
|
|
78
|
+
return !NON_INTERACTIVE_CHANNELS.includes(channel);
|
|
79
|
+
}
|
|
80
|
+
function isInteractiveTurn(turn) {
|
|
81
|
+
if (typeof turn.interactive === "boolean") return turn.interactive;
|
|
82
|
+
return isInteractiveChannel(turn.channel);
|
|
83
|
+
}
|
|
473
84
|
function removeNavigateBlock(input) {
|
|
474
85
|
return input.replace(/::: navigate[\s\S]*?:::/g, "").trim();
|
|
475
86
|
}
|
|
@@ -537,7 +148,7 @@ function transformChatHistoryContentParts(parts) {
|
|
|
537
148
|
function buildDefaultPersona(agentName) {
|
|
538
149
|
return DEFAULT_PERSONA_GUIDE.replace(AGENT_NAME_TOKEN, () => agentName || "My Agent");
|
|
539
150
|
}
|
|
540
|
-
var __defProp2, __name2, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, VoiceNameSchema, PluginProviderSchema, RealtimeProviderSchema, PluginClassSchema, ModelDescriptorSchema, InferenceModelSchema, PluginModelSchema, RealtimeModelSchema, LuaVoiceModelSchema, TurnDetectionSchema, InterruptionSchema, BuiltinAudioClipSchema, AudioConfigSchema, BackgroundAudioEntrySchema, BackgroundAudioSchema, LuaVoiceConfigInnerSchema, LuaVoiceConfigSchema, LuaVoiceRefSchema;
|
|
151
|
+
var __defProp2, __name2, CHANNEL_SEND_CHANNELS, NON_INTERACTIVE_CHANNELS, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, VoiceNameSchema, PluginProviderSchema, RealtimeProviderSchema, PluginClassSchema, ModelDescriptorSchema, InferenceModelSchema, PluginModelSchema, RealtimeModelSchema, LuaVoiceModelSchema, TurnDetectionSchema, InterruptionSchema, BuiltinAudioClipSchema, AudioConfigSchema, BackgroundAudioEntrySchema, BackgroundAudioSchema, LuaVoiceConfigInnerSchema, LuaVoiceConfigSchema, LuaVoiceRefSchema;
|
|
541
152
|
var init_dist = __esm({
|
|
542
153
|
"../shared-types/dist/index.mjs"() {
|
|
543
154
|
"use strict";
|
|
@@ -555,6 +166,23 @@ var init_dist = __esm({
|
|
|
555
166
|
__name2(personaToLiteral, "personaToLiteral");
|
|
556
167
|
__name(aiGenerateInputFromSimplified, "aiGenerateInputFromSimplified");
|
|
557
168
|
__name2(aiGenerateInputFromSimplified, "aiGenerateInputFromSimplified");
|
|
169
|
+
CHANNEL_SEND_CHANNELS = [
|
|
170
|
+
"whatsapp",
|
|
171
|
+
"sms",
|
|
172
|
+
"email",
|
|
173
|
+
"webchat",
|
|
174
|
+
"teams",
|
|
175
|
+
"instagram",
|
|
176
|
+
"messenger"
|
|
177
|
+
];
|
|
178
|
+
NON_INTERACTIVE_CHANNELS = [
|
|
179
|
+
"trigger",
|
|
180
|
+
"agent-invocation"
|
|
181
|
+
];
|
|
182
|
+
__name(isInteractiveChannel, "isInteractiveChannel");
|
|
183
|
+
__name2(isInteractiveChannel, "isInteractiveChannel");
|
|
184
|
+
__name(isInteractiveTurn, "isInteractiveTurn");
|
|
185
|
+
__name2(isInteractiveTurn, "isInteractiveTurn");
|
|
558
186
|
__name(removeNavigateBlock, "removeNavigateBlock");
|
|
559
187
|
__name2(removeNavigateBlock, "removeNavigateBlock");
|
|
560
188
|
__name(transformChatHistoryContentParts, "transformChatHistoryContentParts");
|
|
@@ -796,7 +424,15 @@ Feel free to add, remove, or rename sections. Your persona can be a single parag
|
|
|
796
424
|
// to the LLM as a ToolError — fills the 2–3s gap before the LLM's own
|
|
797
425
|
// recovery response. Persona-specific (keep it short and on-brand);
|
|
798
426
|
// absent → no spoken fallback (the LLM's recovery is the only signal).
|
|
799
|
-
onToolFailureSay: z.string().min(1).max(200).optional()
|
|
427
|
+
onToolFailureSay: z.string().min(1).max(200).optional(),
|
|
428
|
+
// Tool names to withhold from this voice agent's session. Matches ANY
|
|
429
|
+
// resolved tool: the platform base tools (searchKnowledgeBase, searchWeb,
|
|
430
|
+
// geocoding, the send* structured-output family), MCP/device tools, and the
|
|
431
|
+
// agent's own skill tools compiled into the artifact. Typical use is dropping
|
|
432
|
+
// the on-screen send* tools (`sendPayment`, `sendListItems`, …) on a
|
|
433
|
+
// screenless phone agent where they have nowhere to render. Names that match
|
|
434
|
+
// nothing are ignored (warn, not error) so a typo can't fail the push.
|
|
435
|
+
excludeTools: z.array(z.string().min(1)).optional()
|
|
800
436
|
});
|
|
801
437
|
LuaVoiceConfigSchema = LuaVoiceConfigInnerSchema.superRefine((cfg, ctx) => {
|
|
802
438
|
const isRealtime = cfg.llm.kind === "realtime";
|
|
@@ -839,11 +475,408 @@ Feel free to add, remove, or rename sections. Your persona can be a single parag
|
|
|
839
475
|
});
|
|
840
476
|
}
|
|
841
477
|
}
|
|
842
|
-
});
|
|
843
|
-
LuaVoiceRefSchema = z.object({
|
|
844
|
-
voiceId: z.string().min(1),
|
|
845
|
-
version: z.string().optional()
|
|
846
|
-
});
|
|
478
|
+
});
|
|
479
|
+
LuaVoiceRefSchema = z.object({
|
|
480
|
+
voiceId: z.string().min(1),
|
|
481
|
+
version: z.string().optional()
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
// src/interfaces/baskets.ts
|
|
487
|
+
var BasketStatus;
|
|
488
|
+
var init_baskets = __esm({
|
|
489
|
+
"src/interfaces/baskets.ts"() {
|
|
490
|
+
"use strict";
|
|
491
|
+
BasketStatus = /* @__PURE__ */ (function(BasketStatus2) {
|
|
492
|
+
BasketStatus2["ACTIVE"] = "active";
|
|
493
|
+
BasketStatus2["CHECKED_OUT"] = "checked_out";
|
|
494
|
+
BasketStatus2["ABANDONED"] = "abandoned";
|
|
495
|
+
BasketStatus2["EXPIRED"] = "expired";
|
|
496
|
+
return BasketStatus2;
|
|
497
|
+
})({});
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
// src/config/constants.ts
|
|
502
|
+
import { join } from "path";
|
|
503
|
+
import { homedir } from "os";
|
|
504
|
+
var CLI_CONFIG_DIR, VERSION_CHECK_FILE, TELEMETRY_FILE, CLI_CACHE_FILE, BASE_URLS, CREDENTIALS_FILE, SANDBOX_STORAGE_FILE, AUTH_STORAGE_FILE;
|
|
505
|
+
var init_constants = __esm({
|
|
506
|
+
"src/config/constants.ts"() {
|
|
507
|
+
"use strict";
|
|
508
|
+
CLI_CONFIG_DIR = join(homedir(), ".lua-cli");
|
|
509
|
+
VERSION_CHECK_FILE = join(CLI_CONFIG_DIR, "version-check.json");
|
|
510
|
+
TELEMETRY_FILE = join(CLI_CONFIG_DIR, "telemetry.json");
|
|
511
|
+
CLI_CACHE_FILE = join(CLI_CONFIG_DIR, "cache.json");
|
|
512
|
+
BASE_URLS = {
|
|
513
|
+
API: process.env.LUA_API_URL || "https://api.heylua.ai",
|
|
514
|
+
AUTH: process.env.LUA_AUTH_URL || "https://auth.heylua.ai",
|
|
515
|
+
CHAT: process.env.LUA_API_URL || "https://api.heylua.ai",
|
|
516
|
+
WEBHOOK: process.env.LUA_WEBHOOK_URL || "https://webhook.heylua.ai",
|
|
517
|
+
CDN: "https://cdn.heylua.ai"
|
|
518
|
+
};
|
|
519
|
+
CREDENTIALS_FILE = join(CLI_CONFIG_DIR, "credentials");
|
|
520
|
+
SANDBOX_STORAGE_FILE = join(CLI_CONFIG_DIR, "sandbox.json");
|
|
521
|
+
AUTH_STORAGE_FILE = join(CLI_CONFIG_DIR, "auth.json");
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
// src/errors/auth.error.ts
|
|
526
|
+
var AuthenticationError;
|
|
527
|
+
var init_auth_error = __esm({
|
|
528
|
+
"src/errors/auth.error.ts"() {
|
|
529
|
+
"use strict";
|
|
530
|
+
AuthenticationError = class _AuthenticationError extends Error {
|
|
531
|
+
static {
|
|
532
|
+
__name(this, "AuthenticationError");
|
|
533
|
+
}
|
|
534
|
+
statusCode = 401;
|
|
535
|
+
isAuthenticationError = true;
|
|
536
|
+
reason;
|
|
537
|
+
serverMessage;
|
|
538
|
+
/**
|
|
539
|
+
* If true, the error message already contains complete remediation steps
|
|
540
|
+
* and `withErrorHandling` should not append its own hint block. Use this
|
|
541
|
+
* when the throw site has more context about the right fix than the
|
|
542
|
+
* generic per-reason hints (e.g. `getToken()` listing all three ways to
|
|
543
|
+
* configure a key — keychain, env var, .env file).
|
|
544
|
+
*/
|
|
545
|
+
suppressDefaultRemediation;
|
|
546
|
+
constructor(message = "Invalid API key", reason = "unknown", serverMessage, suppressDefaultRemediation = false) {
|
|
547
|
+
super(message);
|
|
548
|
+
this.name = "AuthenticationError";
|
|
549
|
+
this.reason = reason;
|
|
550
|
+
this.serverMessage = serverMessage;
|
|
551
|
+
this.suppressDefaultRemediation = suppressDefaultRemediation;
|
|
552
|
+
if (Error.captureStackTrace) {
|
|
553
|
+
Error.captureStackTrace(this, _AuthenticationError);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Checks if an error is an AuthenticationError
|
|
558
|
+
* @param error - The error to check
|
|
559
|
+
* @returns True if the error is an AuthenticationError
|
|
560
|
+
*/
|
|
561
|
+
static isAuthenticationError(error) {
|
|
562
|
+
return error instanceof _AuthenticationError || error instanceof Error && "isAuthenticationError" in error && error.isAuthenticationError === true;
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
// src/api/http.client.ts
|
|
569
|
+
import { randomUUID } from "crypto";
|
|
570
|
+
var HttpClient;
|
|
571
|
+
var init_http_client = __esm({
|
|
572
|
+
"src/api/http.client.ts"() {
|
|
573
|
+
"use strict";
|
|
574
|
+
init_auth_error();
|
|
575
|
+
HttpClient = class {
|
|
576
|
+
static {
|
|
577
|
+
__name(this, "HttpClient");
|
|
578
|
+
}
|
|
579
|
+
baseUrl;
|
|
580
|
+
/**
|
|
581
|
+
* Creates an instance of HttpClient
|
|
582
|
+
* @param baseUrl - The base URL for all API requests
|
|
583
|
+
*/
|
|
584
|
+
constructor(baseUrl) {
|
|
585
|
+
this.baseUrl = baseUrl;
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Makes an HTTP request with standardized error handling
|
|
589
|
+
* @param url - The full URL to request
|
|
590
|
+
* @param options - Fetch API request options
|
|
591
|
+
* @returns Promise resolving to an ApiResponse with typed data
|
|
592
|
+
* @private
|
|
593
|
+
*/
|
|
594
|
+
async request(url, options = {}) {
|
|
595
|
+
const controller = new AbortController();
|
|
596
|
+
const timeoutId = setTimeout(() => controller.abort(), 3e4);
|
|
597
|
+
try {
|
|
598
|
+
const response = await fetch(url, {
|
|
599
|
+
...options,
|
|
600
|
+
signal: controller.signal,
|
|
601
|
+
headers: {
|
|
602
|
+
"Content-Type": "application/json",
|
|
603
|
+
...options.headers
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
clearTimeout(timeoutId);
|
|
607
|
+
if (!response.ok) {
|
|
608
|
+
let errorData;
|
|
609
|
+
try {
|
|
610
|
+
errorData = await response.json();
|
|
611
|
+
} catch (jsonError) {
|
|
612
|
+
errorData = {};
|
|
613
|
+
}
|
|
614
|
+
if (response.status === 401) {
|
|
615
|
+
const serverMessage = typeof errorData.message === "string" ? errorData.message : void 0;
|
|
616
|
+
if (serverMessage && /not an admin/i.test(serverMessage)) {
|
|
617
|
+
throw new AuthenticationError(`Access denied for this agent: ${serverMessage}`, "no_agent_access", serverMessage);
|
|
618
|
+
}
|
|
619
|
+
const isExplicitCredential = !!serverMessage && /(invalid|expired|missing|no)\s+(api[\s_-]?key|token|credential)/i.test(serverMessage);
|
|
620
|
+
const isBareAuthRejection = !serverMessage || /^unauthorized$/i.test(serverMessage);
|
|
621
|
+
if (isExplicitCredential || isBareAuthRejection) {
|
|
622
|
+
throw new AuthenticationError("Authentication failed. Your API key may be invalid or expired.", "invalid_credentials", serverMessage);
|
|
623
|
+
}
|
|
624
|
+
throw new AuthenticationError(`Authentication failed: ${serverMessage}`, "unknown", serverMessage);
|
|
625
|
+
}
|
|
626
|
+
if (response.status === 403) {
|
|
627
|
+
const detail = errorData.message || "You do not have permission to access this resource.";
|
|
628
|
+
throw new Error(`Access denied (403): ${detail}
|
|
629
|
+
Check that your API key has access to this agent/organization.`);
|
|
630
|
+
}
|
|
631
|
+
return {
|
|
632
|
+
success: false,
|
|
633
|
+
error: {
|
|
634
|
+
message: errorData.message || `HTTP ${response.status}: ${response.statusText}`,
|
|
635
|
+
statusCode: response.status,
|
|
636
|
+
error: errorData.error,
|
|
637
|
+
...errorData
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
let data;
|
|
642
|
+
try {
|
|
643
|
+
data = await response.json();
|
|
644
|
+
} catch (jsonError) {
|
|
645
|
+
data = {};
|
|
646
|
+
}
|
|
647
|
+
if (typeof data === "object" && data !== null && "success" in data) {
|
|
648
|
+
return data;
|
|
649
|
+
}
|
|
650
|
+
return {
|
|
651
|
+
success: true,
|
|
652
|
+
data
|
|
653
|
+
};
|
|
654
|
+
} catch (error) {
|
|
655
|
+
clearTimeout(timeoutId);
|
|
656
|
+
if (AuthenticationError.isAuthenticationError(error)) {
|
|
657
|
+
throw error;
|
|
658
|
+
}
|
|
659
|
+
if (error instanceof Error && error.message.startsWith("Access denied (403)")) {
|
|
660
|
+
throw error;
|
|
661
|
+
}
|
|
662
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
663
|
+
return {
|
|
664
|
+
success: false,
|
|
665
|
+
error: {
|
|
666
|
+
message: "Request timeout (30s)",
|
|
667
|
+
statusCode: 0
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
return {
|
|
672
|
+
success: false,
|
|
673
|
+
error: {
|
|
674
|
+
message: error instanceof Error ? error.message : "Network request failed",
|
|
675
|
+
statusCode: 0
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Checks if an HTTP status code is retryable
|
|
682
|
+
* @param statusCode - The HTTP status code (0 for network errors)
|
|
683
|
+
* @returns True if the request should be retried
|
|
684
|
+
* @private
|
|
685
|
+
*/
|
|
686
|
+
isRetryableStatus(statusCode) {
|
|
687
|
+
return statusCode === 0 || statusCode === 429 || statusCode >= 500 && statusCode <= 504;
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Calculates exponential backoff with full jitter (AWS best practice)
|
|
691
|
+
* @param attempt - The retry attempt number (0-based)
|
|
692
|
+
* @param baseMs - Base delay in milliseconds
|
|
693
|
+
* @param maxMs - Maximum delay cap in milliseconds
|
|
694
|
+
* @returns Delay in milliseconds with random jitter
|
|
695
|
+
* @private
|
|
696
|
+
*/
|
|
697
|
+
calculateBackoff(attempt, baseMs = 1e3, maxMs = 15e3) {
|
|
698
|
+
const exponential = Math.min(maxMs, baseMs * Math.pow(2, attempt));
|
|
699
|
+
return Math.max(100, Math.random() * exponential);
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Wraps request with retry logic for transient failures
|
|
703
|
+
* @param url - The full URL to request
|
|
704
|
+
* @param options - Fetch API request options
|
|
705
|
+
* @param maxRetries - Maximum number of retry attempts (default 3)
|
|
706
|
+
* @returns Promise resolving to an ApiResponse with typed data
|
|
707
|
+
* @private
|
|
708
|
+
*/
|
|
709
|
+
async retryableRequest(url, options = {}, maxRetries = 3) {
|
|
710
|
+
if (options.method === "POST") {
|
|
711
|
+
const headers = options.headers || {};
|
|
712
|
+
if (!headers["X-Idempotency-Key"]) {
|
|
713
|
+
headers["X-Idempotency-Key"] = randomUUID();
|
|
714
|
+
options = {
|
|
715
|
+
...options,
|
|
716
|
+
headers: {
|
|
717
|
+
...options.headers,
|
|
718
|
+
...headers
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
let lastResult = null;
|
|
724
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
725
|
+
try {
|
|
726
|
+
const result = await this.request(url, options);
|
|
727
|
+
if (result.success || !result.error || !this.isRetryableStatus(result.error.statusCode || 0)) {
|
|
728
|
+
return result;
|
|
729
|
+
}
|
|
730
|
+
lastResult = result;
|
|
731
|
+
} catch (error) {
|
|
732
|
+
throw error;
|
|
733
|
+
}
|
|
734
|
+
if (attempt < maxRetries) {
|
|
735
|
+
const backoff = this.calculateBackoff(attempt);
|
|
736
|
+
await new Promise((resolve) => setTimeout(resolve, backoff));
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
return lastResult;
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Performs an HTTP GET request
|
|
743
|
+
* @param url - The relative URL path to request (will be appended to baseUrl)
|
|
744
|
+
* @param headers - Optional HTTP headers to include in the request
|
|
745
|
+
* @returns Promise resolving to an ApiResponse with typed data
|
|
746
|
+
* @protected
|
|
747
|
+
*/
|
|
748
|
+
async httpGet(url, headers) {
|
|
749
|
+
return this.retryableRequest(this.baseUrl + url, {
|
|
750
|
+
method: "GET",
|
|
751
|
+
headers
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Performs an HTTP POST request
|
|
756
|
+
* @param url - The relative URL path to request (will be appended to baseUrl)
|
|
757
|
+
* @param data - Optional request body data (will be JSON stringified)
|
|
758
|
+
* @param headers - Optional HTTP headers to include in the request
|
|
759
|
+
* @returns Promise resolving to an ApiResponse with typed data
|
|
760
|
+
* @protected
|
|
761
|
+
*/
|
|
762
|
+
async httpPost(url, data, headers) {
|
|
763
|
+
return this.retryableRequest(this.baseUrl + url, {
|
|
764
|
+
method: "POST",
|
|
765
|
+
body: data ? JSON.stringify(data) : void 0,
|
|
766
|
+
headers
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Performs an HTTP PUT request
|
|
771
|
+
* @param url - The relative URL path to request (will be appended to baseUrl)
|
|
772
|
+
* @param data - Optional request body data (will be JSON stringified)
|
|
773
|
+
* @param headers - Optional HTTP headers to include in the request
|
|
774
|
+
* @returns Promise resolving to an ApiResponse with typed data
|
|
775
|
+
* @protected
|
|
776
|
+
*/
|
|
777
|
+
async httpPut(url, data, headers) {
|
|
778
|
+
return this.retryableRequest(this.baseUrl + url, {
|
|
779
|
+
method: "PUT",
|
|
780
|
+
body: data ? JSON.stringify(data) : void 0,
|
|
781
|
+
headers
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* Performs an HTTP DELETE request
|
|
786
|
+
* @param url - The relative URL path to request (will be appended to baseUrl)
|
|
787
|
+
* @param headers - Optional HTTP headers to include in the request
|
|
788
|
+
* @returns Promise resolving to an ApiResponse with typed data
|
|
789
|
+
* @protected
|
|
790
|
+
*/
|
|
791
|
+
async httpDelete(url, headers) {
|
|
792
|
+
return this.retryableRequest(this.baseUrl + url, {
|
|
793
|
+
method: "DELETE",
|
|
794
|
+
headers
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* Performs an HTTP PATCH request
|
|
799
|
+
* @param url - The relative URL path to request (will be appended to baseUrl)
|
|
800
|
+
* @param data - Optional request body data (will be JSON stringified)
|
|
801
|
+
* @param headers - Optional HTTP headers to include in the request
|
|
802
|
+
* @returns Promise resolving to an ApiResponse with typed data
|
|
803
|
+
* @protected
|
|
804
|
+
*/
|
|
805
|
+
async httpPatch(url, data, headers) {
|
|
806
|
+
return this.retryableRequest(this.baseUrl + url, {
|
|
807
|
+
method: "PATCH",
|
|
808
|
+
body: data ? JSON.stringify(data) : void 0,
|
|
809
|
+
headers
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
// src/api/auth.api.service.ts
|
|
817
|
+
var init_auth_api_service = __esm({
|
|
818
|
+
"src/api/auth.api.service.ts"() {
|
|
819
|
+
"use strict";
|
|
820
|
+
init_http_client();
|
|
821
|
+
}
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
// src/services/auth.ts
|
|
825
|
+
import "dotenv/config";
|
|
826
|
+
import { readFileSync, writeFileSync, mkdirSync, unlinkSync } from "fs";
|
|
827
|
+
function getToken() {
|
|
828
|
+
if (process.env.LUA_API_KEY) {
|
|
829
|
+
return process.env.LUA_API_KEY;
|
|
830
|
+
}
|
|
831
|
+
try {
|
|
832
|
+
const token = readFileSync(CREDENTIALS_FILE, "utf8").trim();
|
|
833
|
+
if (token) return token;
|
|
834
|
+
} catch {
|
|
835
|
+
}
|
|
836
|
+
throw new AuthenticationError('No API key found.\n\n Authenticate using one of these methods:\n\n \u279C lua auth configure\n \u279C export LUA_API_KEY="your-api-key-here"\n \u279C Add LUA_API_KEY=... to a .env file\n\n \u{1F511} Get your API key at https://admin.heylua.ai', "invalid_credentials", void 0, true);
|
|
837
|
+
}
|
|
838
|
+
var init_auth = __esm({
|
|
839
|
+
"src/services/auth.ts"() {
|
|
840
|
+
"use strict";
|
|
841
|
+
init_auth_api_service();
|
|
842
|
+
init_constants();
|
|
843
|
+
init_auth_error();
|
|
844
|
+
__name(getToken, "getToken");
|
|
845
|
+
}
|
|
846
|
+
});
|
|
847
|
+
|
|
848
|
+
// src/config/compile.constants.ts
|
|
849
|
+
var COMPILE_DIRS, COMPILE_FILES, SKILL_DEFAULTS, YAML_FORMAT;
|
|
850
|
+
var init_compile_constants = __esm({
|
|
851
|
+
"src/config/compile.constants.ts"() {
|
|
852
|
+
"use strict";
|
|
853
|
+
COMPILE_DIRS = {
|
|
854
|
+
DIST: "dist",
|
|
855
|
+
DIST_V2: "dist-v2",
|
|
856
|
+
LUA: ".lua",
|
|
857
|
+
TOOLS: "tools"
|
|
858
|
+
};
|
|
859
|
+
COMPILE_FILES = {
|
|
860
|
+
DEPLOYMENT_JSON: "deployment.json",
|
|
861
|
+
DEPLOY_JSON: "deploy.json",
|
|
862
|
+
MANIFEST_JSON: "manifest.json",
|
|
863
|
+
INDEX_TS: "index.ts",
|
|
864
|
+
INDEX_JS: "index.js",
|
|
865
|
+
PACKAGE_JSON: "package.json",
|
|
866
|
+
TSCONFIG_JSON: "tsconfig.json",
|
|
867
|
+
LUA_SKILL_YAML: "lua.skill.yaml"
|
|
868
|
+
};
|
|
869
|
+
SKILL_DEFAULTS = {
|
|
870
|
+
NAME: "lua-skill",
|
|
871
|
+
VERSION: "1.0.0",
|
|
872
|
+
DESCRIPTION: "",
|
|
873
|
+
CONTEXT: ""
|
|
874
|
+
};
|
|
875
|
+
YAML_FORMAT = {
|
|
876
|
+
INDENT: 2,
|
|
877
|
+
LINE_WIDTH: -1,
|
|
878
|
+
NO_REFS: true
|
|
879
|
+
};
|
|
847
880
|
}
|
|
848
881
|
});
|
|
849
882
|
|
|
@@ -857,6 +890,7 @@ var init_types = __esm({
|
|
|
857
890
|
PrimitiveKind2["SKILL"] = "skill";
|
|
858
891
|
PrimitiveKind2["JOB"] = "job";
|
|
859
892
|
PrimitiveKind2["WEBHOOK"] = "webhook";
|
|
893
|
+
PrimitiveKind2["TRIGGER"] = "trigger";
|
|
860
894
|
PrimitiveKind2["PREPROCESSOR"] = "preprocessor";
|
|
861
895
|
PrimitiveKind2["POSTPROCESSOR"] = "postprocessor";
|
|
862
896
|
PrimitiveKind2["MCP_SERVER"] = "mcp-server";
|
|
@@ -4607,6 +4641,9 @@ var init_agents_api_service = __esm({
|
|
|
4607
4641
|
} : {},
|
|
4608
4642
|
...body.threadId !== void 0 ? {
|
|
4609
4643
|
threadId: body.threadId
|
|
4644
|
+
} : {},
|
|
4645
|
+
...body.webhookPayload !== void 0 ? {
|
|
4646
|
+
webhookPayload: body.webhookPayload
|
|
4610
4647
|
} : {}
|
|
4611
4648
|
};
|
|
4612
4649
|
}
|
|
@@ -4989,6 +5026,30 @@ var init_voice_api_service = __esm({
|
|
|
4989
5026
|
});
|
|
4990
5027
|
}
|
|
4991
5028
|
/**
|
|
5029
|
+
* Create a voice room + client access token for a custom frontend
|
|
5030
|
+
* (standard livekit-client). The session runs under a synthetic identity;
|
|
5031
|
+
* pass `userId` to scope conversation memory + transcript to your own end
|
|
5032
|
+
* user. Wraps `POST /developer/voice/:agentId/session`.
|
|
5033
|
+
*/
|
|
5034
|
+
async createSession(input = {}) {
|
|
5035
|
+
return this.httpPost(`/developer/voice/${this.agentId}/session`, input, {
|
|
5036
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
5037
|
+
});
|
|
5038
|
+
}
|
|
5039
|
+
/**
|
|
5040
|
+
* Sandbox helper: throws on non-success and returns the unwrapped output.
|
|
5041
|
+
*/
|
|
5042
|
+
async createSessionForSandbox(input = {}) {
|
|
5043
|
+
const result = await this.createSession(input);
|
|
5044
|
+
if (!result.success) {
|
|
5045
|
+
throw new Error(result.error?.message || "Voice session creation failed");
|
|
5046
|
+
}
|
|
5047
|
+
if (!result.data) {
|
|
5048
|
+
throw new Error("Voice session creation failed: empty response");
|
|
5049
|
+
}
|
|
5050
|
+
return result.data;
|
|
5051
|
+
}
|
|
5052
|
+
/**
|
|
4992
5053
|
* Sandbox helper: throws on non-success and returns the unwrapped output.
|
|
4993
5054
|
* Mirrors the shape `AgentsApiService.invokeForSandbox` exposes so the
|
|
4994
5055
|
* `Voice` namespace in `api-exports.ts` stays a one-liner.
|
|
@@ -5007,6 +5068,79 @@ var init_voice_api_service = __esm({
|
|
|
5007
5068
|
}
|
|
5008
5069
|
});
|
|
5009
5070
|
|
|
5071
|
+
// src/api/channels-send.api.service.ts
|
|
5072
|
+
var ChannelsSendApiService;
|
|
5073
|
+
var init_channels_send_api_service = __esm({
|
|
5074
|
+
"src/api/channels-send.api.service.ts"() {
|
|
5075
|
+
"use strict";
|
|
5076
|
+
init_http_client();
|
|
5077
|
+
ChannelsSendApiService = class extends HttpClient {
|
|
5078
|
+
static {
|
|
5079
|
+
__name(this, "ChannelsSendApiService");
|
|
5080
|
+
}
|
|
5081
|
+
apiKey;
|
|
5082
|
+
agentId;
|
|
5083
|
+
constructor(baseUrl, apiKey, agentId) {
|
|
5084
|
+
super(baseUrl), this.apiKey = apiKey, this.agentId = agentId;
|
|
5085
|
+
}
|
|
5086
|
+
/** POST /developer/agents/:agentId/channels/send */
|
|
5087
|
+
async send(input) {
|
|
5088
|
+
return this.httpPost(`/developer/agents/${this.agentId}/channels/send`, input, {
|
|
5089
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
5090
|
+
});
|
|
5091
|
+
}
|
|
5092
|
+
/** POST /developer/agents/:agentId/channels/whatsapp/template */
|
|
5093
|
+
async sendWhatsAppTemplate(input) {
|
|
5094
|
+
return this.httpPost(`/developer/agents/${this.agentId}/channels/whatsapp/template`, input, {
|
|
5095
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
5096
|
+
});
|
|
5097
|
+
}
|
|
5098
|
+
/** POST /developer/agents/:agentId/channels/email/send */
|
|
5099
|
+
async sendEmail(input) {
|
|
5100
|
+
return this.httpPost(`/developer/agents/${this.agentId}/channels/email/send`, input, {
|
|
5101
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
5102
|
+
});
|
|
5103
|
+
}
|
|
5104
|
+
/**
|
|
5105
|
+
* Sandbox helper: throws on non-success, returns unwrapped output.
|
|
5106
|
+
* A 200 with `persisted: false` is NOT an error — it passes through.
|
|
5107
|
+
*/
|
|
5108
|
+
async sendForSandbox(input) {
|
|
5109
|
+
const result = await this.send(input);
|
|
5110
|
+
if (!result.success) {
|
|
5111
|
+
throw new Error(result.error?.message || "Channel send failed");
|
|
5112
|
+
}
|
|
5113
|
+
if (!result.data) {
|
|
5114
|
+
throw new Error("Channel send failed: empty response");
|
|
5115
|
+
}
|
|
5116
|
+
return result.data;
|
|
5117
|
+
}
|
|
5118
|
+
/** Sandbox helper for WhatsApp template sends. */
|
|
5119
|
+
async sendWhatsAppTemplateForSandbox(input) {
|
|
5120
|
+
const result = await this.sendWhatsAppTemplate(input);
|
|
5121
|
+
if (!result.success) {
|
|
5122
|
+
throw new Error(result.error?.message || "WhatsApp template send failed");
|
|
5123
|
+
}
|
|
5124
|
+
if (!result.data) {
|
|
5125
|
+
throw new Error("WhatsApp template send failed: empty response");
|
|
5126
|
+
}
|
|
5127
|
+
return result.data;
|
|
5128
|
+
}
|
|
5129
|
+
/** Sandbox helper for email sends. */
|
|
5130
|
+
async sendEmailForSandbox(input) {
|
|
5131
|
+
const result = await this.sendEmail(input);
|
|
5132
|
+
if (!result.success) {
|
|
5133
|
+
throw new Error(result.error?.message || "Email send failed");
|
|
5134
|
+
}
|
|
5135
|
+
if (!result.data) {
|
|
5136
|
+
throw new Error("Email send failed: empty response");
|
|
5137
|
+
}
|
|
5138
|
+
return result.data;
|
|
5139
|
+
}
|
|
5140
|
+
};
|
|
5141
|
+
}
|
|
5142
|
+
});
|
|
5143
|
+
|
|
5010
5144
|
// src/api/device.api.service.ts
|
|
5011
5145
|
var device_api_service_exports = {};
|
|
5012
5146
|
__export(device_api_service_exports, {
|
|
@@ -5099,6 +5233,7 @@ __export(lazy_instances_exports, {
|
|
|
5099
5233
|
getAiInstance: () => getAiInstance,
|
|
5100
5234
|
getBasketsInstance: () => getBasketsInstance,
|
|
5101
5235
|
getCdnInstance: () => getCdnInstance,
|
|
5236
|
+
getChannelsSendInstance: () => getChannelsSendInstance,
|
|
5102
5237
|
getDataInstance: () => getDataInstance,
|
|
5103
5238
|
getDeveloperInstance: () => getDeveloperInstance,
|
|
5104
5239
|
getDeviceInstance: () => getDeviceInstance,
|
|
@@ -5209,6 +5344,13 @@ async function getVoiceInstance() {
|
|
|
5209
5344
|
}
|
|
5210
5345
|
return _voiceInstance;
|
|
5211
5346
|
}
|
|
5347
|
+
async function getChannelsSendInstance() {
|
|
5348
|
+
if (!_channelsSendInstance) {
|
|
5349
|
+
const creds = await getCredentials();
|
|
5350
|
+
_channelsSendInstance = new ChannelsSendApiService(BASE_URLS.API, creds.apiKey, creds.agentId);
|
|
5351
|
+
}
|
|
5352
|
+
return _channelsSendInstance;
|
|
5353
|
+
}
|
|
5212
5354
|
function clearAllInstances() {
|
|
5213
5355
|
_userInstance = null;
|
|
5214
5356
|
_dataInstance = null;
|
|
@@ -5223,8 +5365,9 @@ function clearAllInstances() {
|
|
|
5223
5365
|
_cdnInstance = null;
|
|
5224
5366
|
_developerInstance = null;
|
|
5225
5367
|
_voiceInstance = null;
|
|
5368
|
+
_channelsSendInstance = null;
|
|
5226
5369
|
}
|
|
5227
|
-
var _userInstance, _dataInstance, _productsInstance, _basketsInstance, _orderInstance, _webhookInstance, _jobInstance, _aiInstance, _agentsInstance, _whatsAppTemplatesInstance, _cdnInstance, _developerInstance, _voiceInstance, _deviceInstance;
|
|
5370
|
+
var _userInstance, _dataInstance, _productsInstance, _basketsInstance, _orderInstance, _webhookInstance, _jobInstance, _aiInstance, _agentsInstance, _whatsAppTemplatesInstance, _cdnInstance, _developerInstance, _voiceInstance, _channelsSendInstance, _deviceInstance;
|
|
5228
5371
|
var init_lazy_instances = __esm({
|
|
5229
5372
|
"src/api/lazy-instances.ts"() {
|
|
5230
5373
|
"use strict";
|
|
@@ -5243,6 +5386,7 @@ var init_lazy_instances = __esm({
|
|
|
5243
5386
|
init_cdn_api_service();
|
|
5244
5387
|
init_developer_api_service();
|
|
5245
5388
|
init_voice_api_service();
|
|
5389
|
+
init_channels_send_api_service();
|
|
5246
5390
|
_userInstance = null;
|
|
5247
5391
|
_dataInstance = null;
|
|
5248
5392
|
_productsInstance = null;
|
|
@@ -5256,6 +5400,7 @@ var init_lazy_instances = __esm({
|
|
|
5256
5400
|
_cdnInstance = null;
|
|
5257
5401
|
_developerInstance = null;
|
|
5258
5402
|
_voiceInstance = null;
|
|
5403
|
+
_channelsSendInstance = null;
|
|
5259
5404
|
__name(getUserInstance, "getUserInstance");
|
|
5260
5405
|
__name(getDataInstance, "getDataInstance");
|
|
5261
5406
|
__name(getProductsInstance, "getProductsInstance");
|
|
@@ -5271,6 +5416,7 @@ var init_lazy_instances = __esm({
|
|
|
5271
5416
|
__name(getDeviceInstance, "getDeviceInstance");
|
|
5272
5417
|
__name(getDeveloperInstance, "getDeveloperInstance");
|
|
5273
5418
|
__name(getVoiceInstance, "getVoiceInstance");
|
|
5419
|
+
__name(getChannelsSendInstance, "getChannelsSendInstance");
|
|
5274
5420
|
__name(clearAllInstances, "clearAllInstances");
|
|
5275
5421
|
}
|
|
5276
5422
|
});
|
|
@@ -5557,6 +5703,39 @@ var LuaWebhook = class {
|
|
|
5557
5703
|
return this.executeFunction(event);
|
|
5558
5704
|
}
|
|
5559
5705
|
};
|
|
5706
|
+
var LuaTrigger = class {
|
|
5707
|
+
static {
|
|
5708
|
+
__name(this, "LuaTrigger");
|
|
5709
|
+
}
|
|
5710
|
+
name;
|
|
5711
|
+
description;
|
|
5712
|
+
source;
|
|
5713
|
+
inputSchema;
|
|
5714
|
+
verify;
|
|
5715
|
+
filter;
|
|
5716
|
+
transform;
|
|
5717
|
+
constructor(config) {
|
|
5718
|
+
if (!config.name || !config.name.trim()) {
|
|
5719
|
+
throw new Error("LuaTrigger requires a non-empty `name` (used as the server-side identifier).");
|
|
5720
|
+
}
|
|
5721
|
+
if (!config.verify && !config.filter && !config.transform) {
|
|
5722
|
+
throw new Error("LuaTrigger requires at least one of verify, filter, or transform.");
|
|
5723
|
+
}
|
|
5724
|
+
this.name = config.name;
|
|
5725
|
+
this.description = config.description;
|
|
5726
|
+
this.source = config.source ?? "webhook";
|
|
5727
|
+
this.inputSchema = config.inputSchema;
|
|
5728
|
+
this.verify = config.verify;
|
|
5729
|
+
this.filter = config.filter;
|
|
5730
|
+
this.transform = config.transform;
|
|
5731
|
+
}
|
|
5732
|
+
getName() {
|
|
5733
|
+
return this.name;
|
|
5734
|
+
}
|
|
5735
|
+
getDescription() {
|
|
5736
|
+
return this.description;
|
|
5737
|
+
}
|
|
5738
|
+
};
|
|
5560
5739
|
var PreProcessor = class {
|
|
5561
5740
|
static {
|
|
5562
5741
|
__name(this, "PreProcessor");
|
|
@@ -5712,6 +5891,7 @@ var LuaAgent = class {
|
|
|
5712
5891
|
modelSettings;
|
|
5713
5892
|
skills;
|
|
5714
5893
|
webhooks;
|
|
5894
|
+
triggers;
|
|
5715
5895
|
jobs;
|
|
5716
5896
|
preProcessors;
|
|
5717
5897
|
postProcessors;
|
|
@@ -5752,6 +5932,7 @@ var LuaAgent = class {
|
|
|
5752
5932
|
}
|
|
5753
5933
|
this.skills = config.skills || [];
|
|
5754
5934
|
this.webhooks = config.webhooks || [];
|
|
5935
|
+
this.triggers = config.triggers || [];
|
|
5755
5936
|
this.jobs = config.jobs || [];
|
|
5756
5937
|
this.preProcessors = config.preProcessors || [];
|
|
5757
5938
|
this.postProcessors = config.postProcessors || [];
|
|
@@ -5780,6 +5961,9 @@ var LuaAgent = class {
|
|
|
5780
5961
|
getWebhooks() {
|
|
5781
5962
|
return this.webhooks;
|
|
5782
5963
|
}
|
|
5964
|
+
getTriggers() {
|
|
5965
|
+
return this.triggers;
|
|
5966
|
+
}
|
|
5783
5967
|
getJobs() {
|
|
5784
5968
|
return this.jobs;
|
|
5785
5969
|
}
|
|
@@ -5879,6 +6063,7 @@ var LuaVoice = class {
|
|
|
5879
6063
|
preemptiveGeneration;
|
|
5880
6064
|
interruption;
|
|
5881
6065
|
sttLanguage;
|
|
6066
|
+
excludeTools;
|
|
5882
6067
|
tools;
|
|
5883
6068
|
onEnter;
|
|
5884
6069
|
onUserTurnCompleted;
|
|
@@ -5901,6 +6086,7 @@ var LuaVoice = class {
|
|
|
5901
6086
|
this.preemptiveGeneration = config.preemptiveGeneration;
|
|
5902
6087
|
this.interruption = config.interruption;
|
|
5903
6088
|
this.sttLanguage = config.sttLanguage;
|
|
6089
|
+
this.excludeTools = config.excludeTools;
|
|
5904
6090
|
this.tools = Object.freeze([
|
|
5905
6091
|
...config.tools ?? []
|
|
5906
6092
|
]);
|
|
@@ -5915,6 +6101,7 @@ function defineVoice(config) {
|
|
|
5915
6101
|
__name(defineVoice, "defineVoice");
|
|
5916
6102
|
|
|
5917
6103
|
// src/api-exports.ts
|
|
6104
|
+
init_dist();
|
|
5918
6105
|
init_baskets();
|
|
5919
6106
|
|
|
5920
6107
|
// src/interfaces/orders.ts
|
|
@@ -6398,6 +6585,32 @@ var Voice = {
|
|
|
6398
6585
|
const { getVoiceInstance: getVoiceInstance2 } = await Promise.resolve().then(() => (init_lazy_instances(), lazy_instances_exports));
|
|
6399
6586
|
const voice = await getVoiceInstance2();
|
|
6400
6587
|
return voice.dispatchForSandbox(input);
|
|
6588
|
+
},
|
|
6589
|
+
async createSession(input) {
|
|
6590
|
+
const { getVoiceInstance: getVoiceInstance2 } = await Promise.resolve().then(() => (init_lazy_instances(), lazy_instances_exports));
|
|
6591
|
+
const voice = await getVoiceInstance2();
|
|
6592
|
+
return voice.createSessionForSandbox(input ?? {});
|
|
6593
|
+
}
|
|
6594
|
+
};
|
|
6595
|
+
var Channels = {
|
|
6596
|
+
async send(input) {
|
|
6597
|
+
const { getChannelsSendInstance: getChannelsSendInstance2 } = await Promise.resolve().then(() => (init_lazy_instances(), lazy_instances_exports));
|
|
6598
|
+
const channels = await getChannelsSendInstance2();
|
|
6599
|
+
return channels.sendForSandbox(input);
|
|
6600
|
+
},
|
|
6601
|
+
whatsapp: {
|
|
6602
|
+
async sendTemplate(input) {
|
|
6603
|
+
const { getChannelsSendInstance: getChannelsSendInstance2 } = await Promise.resolve().then(() => (init_lazy_instances(), lazy_instances_exports));
|
|
6604
|
+
const channels = await getChannelsSendInstance2();
|
|
6605
|
+
return channels.sendWhatsAppTemplateForSandbox(input);
|
|
6606
|
+
}
|
|
6607
|
+
},
|
|
6608
|
+
email: {
|
|
6609
|
+
async send(input) {
|
|
6610
|
+
const { getChannelsSendInstance: getChannelsSendInstance2 } = await Promise.resolve().then(() => (init_lazy_instances(), lazy_instances_exports));
|
|
6611
|
+
const channels = await getChannelsSendInstance2();
|
|
6612
|
+
return channels.sendEmailForSandbox(input);
|
|
6613
|
+
}
|
|
6401
6614
|
}
|
|
6402
6615
|
};
|
|
6403
6616
|
var Templates = {
|
|
@@ -6531,6 +6744,10 @@ function defineDeviceTrigger(config) {
|
|
|
6531
6744
|
return new LuaDeviceTrigger(config);
|
|
6532
6745
|
}
|
|
6533
6746
|
__name(defineDeviceTrigger, "defineDeviceTrigger");
|
|
6747
|
+
function defineTrigger(config) {
|
|
6748
|
+
return new LuaTrigger(config);
|
|
6749
|
+
}
|
|
6750
|
+
__name(defineTrigger, "defineTrigger");
|
|
6534
6751
|
export {
|
|
6535
6752
|
AI,
|
|
6536
6753
|
Agents,
|
|
@@ -6538,6 +6755,8 @@ export {
|
|
|
6538
6755
|
BasketStatus,
|
|
6539
6756
|
Baskets,
|
|
6540
6757
|
CDN,
|
|
6758
|
+
CHANNEL_SEND_CHANNELS,
|
|
6759
|
+
Channels,
|
|
6541
6760
|
Data,
|
|
6542
6761
|
DataEntryInstance,
|
|
6543
6762
|
JobInstance,
|
|
@@ -6551,6 +6770,7 @@ export {
|
|
|
6551
6770
|
PostProcessor as LuaPostprocessor,
|
|
6552
6771
|
PreProcessor as LuaPreprocessor,
|
|
6553
6772
|
LuaSkill,
|
|
6773
|
+
LuaTrigger,
|
|
6554
6774
|
LuaVoice,
|
|
6555
6775
|
LuaVoiceTool,
|
|
6556
6776
|
LuaWebhook,
|
|
@@ -6568,6 +6788,7 @@ export {
|
|
|
6568
6788
|
Voice,
|
|
6569
6789
|
defineDevice,
|
|
6570
6790
|
defineDeviceTrigger,
|
|
6791
|
+
defineTrigger,
|
|
6571
6792
|
defineVoice,
|
|
6572
6793
|
env
|
|
6573
6794
|
};
|