lua-cli 3.0.0-alpha.5 ā 3.0.0-alpha.6
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/commands/push.d.ts +2 -5
- package/dist/commands/push.js +177 -48
- package/package.json +1 -1
- package/template/lua.skill.yaml +36 -14
- package/template/package.json +1 -1
package/dist/commands/push.d.ts
CHANGED
|
@@ -18,10 +18,7 @@
|
|
|
18
18
|
* Note: This does NOT deploy to production. Use `lua deploy` for that.
|
|
19
19
|
*
|
|
20
20
|
* @param type - Optional type argument ('skill', 'persona', 'webhook', 'job', 'preprocessor', 'postprocessor', or 'all')
|
|
21
|
-
* @param
|
|
21
|
+
* @param cmdObj - Commander command object with options
|
|
22
22
|
* @returns Promise that resolves when push completes
|
|
23
23
|
*/
|
|
24
|
-
export declare function pushCommand(type?: string,
|
|
25
|
-
force?: boolean;
|
|
26
|
-
autoDeploy?: boolean;
|
|
27
|
-
}): Promise<void>;
|
|
24
|
+
export declare function pushCommand(type?: string, cmdObj?: any): Promise<void>;
|
package/dist/commands/push.js
CHANGED
|
@@ -32,15 +32,20 @@ import PostProcessorApi from '../api/postprocessor.api.service.js';
|
|
|
32
32
|
* Note: This does NOT deploy to production. Use `lua deploy` for that.
|
|
33
33
|
*
|
|
34
34
|
* @param type - Optional type argument ('skill', 'persona', 'webhook', 'job', 'preprocessor', 'postprocessor', or 'all')
|
|
35
|
-
* @param
|
|
35
|
+
* @param cmdObj - Commander command object with options
|
|
36
36
|
* @returns Promise that resolves when push completes
|
|
37
37
|
*/
|
|
38
|
-
export async function pushCommand(type,
|
|
38
|
+
export async function pushCommand(type, cmdObj) {
|
|
39
39
|
return withErrorHandling(async () => {
|
|
40
|
+
// Extract options from Commander command object
|
|
41
|
+
const options = {
|
|
42
|
+
force: cmdObj?.force || false,
|
|
43
|
+
autoDeploy: cmdObj?.autoDeploy || false
|
|
44
|
+
};
|
|
40
45
|
let selectedType;
|
|
41
46
|
// Handle 'all' type with force flag
|
|
42
47
|
if (type === 'all') {
|
|
43
|
-
if (!options
|
|
48
|
+
if (!options.force) {
|
|
44
49
|
console.error('ā The "all" type requires the --force flag');
|
|
45
50
|
console.log('\nUsage:');
|
|
46
51
|
console.log(' lua push all --force Push all components without prompts');
|
|
@@ -1058,6 +1063,9 @@ async function deployVersionAfterPush(apiKey, agentId, selectedSkill, pushedVers
|
|
|
1058
1063
|
*/
|
|
1059
1064
|
async function pushAllCommand(options) {
|
|
1060
1065
|
writeProgress("š Push All - Pushing all components to server...\n");
|
|
1066
|
+
if (options.autoDeploy) {
|
|
1067
|
+
writeInfo("š Auto-deploy to production is ENABLED\n");
|
|
1068
|
+
}
|
|
1061
1069
|
// Step 1: Compile first
|
|
1062
1070
|
writeProgress("š¦ Compiling project...");
|
|
1063
1071
|
await compileCommand();
|
|
@@ -1080,7 +1088,24 @@ async function pushAllCommand(options) {
|
|
|
1080
1088
|
process.exit(1);
|
|
1081
1089
|
}
|
|
1082
1090
|
const deployData = JSON.parse(fs.readFileSync(deployJsonPath, 'utf8'));
|
|
1083
|
-
//
|
|
1091
|
+
// Step 3b: Read bundled webhooks and jobs from dist/
|
|
1092
|
+
const webhooksJsonPath = path.join(process.cwd(), 'dist', 'webhooks.json');
|
|
1093
|
+
const jobsJsonPath = path.join(process.cwd(), 'dist', 'jobs.json');
|
|
1094
|
+
const preprocessorsJsonPath = path.join(process.cwd(), 'dist', 'preprocessors.json');
|
|
1095
|
+
const postprocessorsJsonPath = path.join(process.cwd(), 'dist', 'postprocessors.json');
|
|
1096
|
+
const bundledWebhooks = fs.existsSync(webhooksJsonPath)
|
|
1097
|
+
? JSON.parse(fs.readFileSync(webhooksJsonPath, 'utf8'))
|
|
1098
|
+
: [];
|
|
1099
|
+
const bundledJobs = fs.existsSync(jobsJsonPath)
|
|
1100
|
+
? JSON.parse(fs.readFileSync(jobsJsonPath, 'utf8'))
|
|
1101
|
+
: [];
|
|
1102
|
+
const bundledPreprocessors = fs.existsSync(preprocessorsJsonPath)
|
|
1103
|
+
? JSON.parse(fs.readFileSync(preprocessorsJsonPath, 'utf8'))
|
|
1104
|
+
: [];
|
|
1105
|
+
const bundledPostprocessors = fs.existsSync(postprocessorsJsonPath)
|
|
1106
|
+
? JSON.parse(fs.readFileSync(postprocessorsJsonPath, 'utf8'))
|
|
1107
|
+
: [];
|
|
1108
|
+
// Track results for both push and deploy
|
|
1084
1109
|
const results = {
|
|
1085
1110
|
skills: [],
|
|
1086
1111
|
webhooks: [],
|
|
@@ -1088,6 +1113,12 @@ async function pushAllCommand(options) {
|
|
|
1088
1113
|
preprocessors: [],
|
|
1089
1114
|
postprocessors: []
|
|
1090
1115
|
};
|
|
1116
|
+
// Track what needs to be deployed
|
|
1117
|
+
const toDeploySkills = [];
|
|
1118
|
+
const toDeployWebhooks = [];
|
|
1119
|
+
const toDeployJobs = [];
|
|
1120
|
+
const toDeployPreprocessors = [];
|
|
1121
|
+
const toDeployPostprocessors = [];
|
|
1091
1122
|
// Step 4: Push all skills
|
|
1092
1123
|
if (config.skills && config.skills.length > 0) {
|
|
1093
1124
|
writeProgress(`\nš¦ Pushing ${config.skills.length} skill(s)...`);
|
|
@@ -1122,14 +1153,17 @@ async function pushAllCommand(options) {
|
|
|
1122
1153
|
inputSchema: skillData.inputSchema,
|
|
1123
1154
|
outputSchema: skillData.outputSchema,
|
|
1124
1155
|
});
|
|
1156
|
+
if (!pushResult.success) {
|
|
1157
|
+
console.error(` ā Failed to push ${skillConfig.name}:`, pushResult.error?.message);
|
|
1158
|
+
continue;
|
|
1159
|
+
}
|
|
1125
1160
|
// Update YAML with new version
|
|
1126
1161
|
updateSkillVersionInYaml(skillConfig.name, newVersion);
|
|
1127
1162
|
results.skills.push({ name: skillConfig.name, version: newVersion, skillId });
|
|
1128
1163
|
writeSuccess(` ā
${skillConfig.name} v${newVersion} pushed`);
|
|
1129
|
-
//
|
|
1164
|
+
// Queue for deployment if requested
|
|
1130
1165
|
if (options.autoDeploy) {
|
|
1131
|
-
|
|
1132
|
-
writeSuccess(` š ${skillConfig.name} v${newVersion} deployed to production`);
|
|
1166
|
+
toDeploySkills.push({ skillId, version: newVersion, name: skillConfig.name });
|
|
1133
1167
|
}
|
|
1134
1168
|
}
|
|
1135
1169
|
catch (error) {
|
|
@@ -1142,9 +1176,9 @@ async function pushAllCommand(options) {
|
|
|
1142
1176
|
writeProgress(`\nšŖ Pushing ${config.webhooks.length} webhook(s)...`);
|
|
1143
1177
|
for (const webhookConfig of config.webhooks) {
|
|
1144
1178
|
try {
|
|
1145
|
-
const webhookData =
|
|
1179
|
+
const webhookData = bundledWebhooks.find((w) => w.name === webhookConfig.name);
|
|
1146
1180
|
if (!webhookData) {
|
|
1147
|
-
console.warn(`ā ļø Webhook "${webhookConfig.name}" not found in
|
|
1181
|
+
console.warn(`ā ļø Webhook "${webhookConfig.name}" not found in compiled data, skipping`);
|
|
1148
1182
|
continue;
|
|
1149
1183
|
}
|
|
1150
1184
|
// Validate webhookId and version exist
|
|
@@ -1188,18 +1222,9 @@ async function pushAllCommand(options) {
|
|
|
1188
1222
|
updateWebhookVersionInYaml(webhookConfig.name, newVersion);
|
|
1189
1223
|
results.webhooks.push({ name: webhookConfig.name, version: newVersion });
|
|
1190
1224
|
writeSuccess(` ā
${webhookConfig.name} v${newVersion} pushed`);
|
|
1191
|
-
//
|
|
1225
|
+
// Queue for deployment if requested
|
|
1192
1226
|
if (options.autoDeploy) {
|
|
1193
|
-
|
|
1194
|
-
method: 'PUT',
|
|
1195
|
-
headers: {
|
|
1196
|
-
'Authorization': `Bearer ${apiKey}`,
|
|
1197
|
-
'Content-Type': 'application/json'
|
|
1198
|
-
}
|
|
1199
|
-
});
|
|
1200
|
-
if (deployResponse.ok) {
|
|
1201
|
-
writeSuccess(` š ${webhookConfig.name} v${newVersion} deployed to production`);
|
|
1202
|
-
}
|
|
1227
|
+
toDeployWebhooks.push({ webhookId: webhookConfig.webhookId, version: newVersion, name: webhookConfig.name });
|
|
1203
1228
|
}
|
|
1204
1229
|
}
|
|
1205
1230
|
catch (error) {
|
|
@@ -1212,9 +1237,9 @@ async function pushAllCommand(options) {
|
|
|
1212
1237
|
writeProgress(`\nā° Pushing ${config.jobs.length} job(s)...`);
|
|
1213
1238
|
for (const jobConfig of config.jobs) {
|
|
1214
1239
|
try {
|
|
1215
|
-
const jobData =
|
|
1240
|
+
const jobData = bundledJobs.find((j) => j.name === jobConfig.name);
|
|
1216
1241
|
if (!jobData) {
|
|
1217
|
-
console.warn(`ā ļø Job "${jobConfig.name}" not found in
|
|
1242
|
+
console.warn(`ā ļø Job "${jobConfig.name}" not found in compiled data, skipping`);
|
|
1218
1243
|
continue;
|
|
1219
1244
|
}
|
|
1220
1245
|
// Validate jobId and version exist
|
|
@@ -1259,18 +1284,9 @@ async function pushAllCommand(options) {
|
|
|
1259
1284
|
updateJobVersionInYaml(jobConfig.name, newVersion);
|
|
1260
1285
|
results.jobs.push({ name: jobConfig.name, version: newVersion });
|
|
1261
1286
|
writeSuccess(` ā
${jobConfig.name} v${newVersion} pushed`);
|
|
1262
|
-
//
|
|
1287
|
+
// Queue for deployment if requested
|
|
1263
1288
|
if (options.autoDeploy) {
|
|
1264
|
-
|
|
1265
|
-
method: 'PUT',
|
|
1266
|
-
headers: {
|
|
1267
|
-
'Authorization': `Bearer ${apiKey}`,
|
|
1268
|
-
'Content-Type': 'application/json'
|
|
1269
|
-
}
|
|
1270
|
-
});
|
|
1271
|
-
if (deployResponse.ok) {
|
|
1272
|
-
writeSuccess(` š ${jobConfig.name} v${newVersion} deployed to production`);
|
|
1273
|
-
}
|
|
1289
|
+
toDeployJobs.push({ jobId: jobConfig.jobId, version: newVersion, name: jobConfig.name });
|
|
1274
1290
|
}
|
|
1275
1291
|
}
|
|
1276
1292
|
catch (error) {
|
|
@@ -1284,9 +1300,9 @@ async function pushAllCommand(options) {
|
|
|
1284
1300
|
const preprocessorService = new PreProcessorApi(BASE_URLS.API, apiKey, agentId);
|
|
1285
1301
|
for (const processorConfig of config.preprocessors) {
|
|
1286
1302
|
try {
|
|
1287
|
-
const processorData =
|
|
1303
|
+
const processorData = bundledPreprocessors.find((p) => p.name === processorConfig.name);
|
|
1288
1304
|
if (!processorData) {
|
|
1289
|
-
console.warn(`ā ļø Preprocessor "${processorConfig.name}" not found in
|
|
1305
|
+
console.warn(`ā ļø Preprocessor "${processorConfig.name}" not found in compiled data, skipping`);
|
|
1290
1306
|
continue;
|
|
1291
1307
|
}
|
|
1292
1308
|
// Validate preprocessorId and version exist
|
|
@@ -1323,12 +1339,9 @@ async function pushAllCommand(options) {
|
|
|
1323
1339
|
updateProcessorVersionInYaml('preprocessors', processorConfig.name, newVersion);
|
|
1324
1340
|
results.preprocessors.push({ name: processorConfig.name, version: newVersion });
|
|
1325
1341
|
writeSuccess(` ā
${processorConfig.name} v${newVersion} pushed`);
|
|
1326
|
-
//
|
|
1342
|
+
// Queue for deployment if requested
|
|
1327
1343
|
if (options.autoDeploy) {
|
|
1328
|
-
|
|
1329
|
-
if (deployResult.success) {
|
|
1330
|
-
writeSuccess(` š ${processorConfig.name} v${newVersion} deployed to production`);
|
|
1331
|
-
}
|
|
1344
|
+
toDeployPreprocessors.push({ preprocessorId, version: newVersion, name: processorConfig.name });
|
|
1332
1345
|
}
|
|
1333
1346
|
}
|
|
1334
1347
|
catch (error) {
|
|
@@ -1342,9 +1355,9 @@ async function pushAllCommand(options) {
|
|
|
1342
1355
|
const postprocessorService = new PostProcessorApi(BASE_URLS.API, apiKey, agentId);
|
|
1343
1356
|
for (const processorConfig of config.postprocessors) {
|
|
1344
1357
|
try {
|
|
1345
|
-
const processorData =
|
|
1358
|
+
const processorData = bundledPostprocessors.find((p) => p.name === processorConfig.name);
|
|
1346
1359
|
if (!processorData) {
|
|
1347
|
-
console.warn(`ā ļø Postprocessor "${processorConfig.name}" not found in
|
|
1360
|
+
console.warn(`ā ļø Postprocessor "${processorConfig.name}" not found in compiled data, skipping`);
|
|
1348
1361
|
continue;
|
|
1349
1362
|
}
|
|
1350
1363
|
// Validate postprocessorId and version exist
|
|
@@ -1381,12 +1394,9 @@ async function pushAllCommand(options) {
|
|
|
1381
1394
|
updateProcessorVersionInYaml('postprocessors', processorConfig.name, newVersion);
|
|
1382
1395
|
results.postprocessors.push({ name: processorConfig.name, version: newVersion });
|
|
1383
1396
|
writeSuccess(` ā
${processorConfig.name} v${newVersion} pushed`);
|
|
1384
|
-
//
|
|
1397
|
+
// Queue for deployment if requested
|
|
1385
1398
|
if (options.autoDeploy) {
|
|
1386
|
-
|
|
1387
|
-
if (deployResult.success) {
|
|
1388
|
-
writeSuccess(` š ${processorConfig.name} v${newVersion} deployed to production`);
|
|
1389
|
-
}
|
|
1399
|
+
toDeployPostprocessors.push({ postprocessorId, version: newVersion, name: processorConfig.name });
|
|
1390
1400
|
}
|
|
1391
1401
|
}
|
|
1392
1402
|
catch (error) {
|
|
@@ -1394,7 +1404,104 @@ async function pushAllCommand(options) {
|
|
|
1394
1404
|
}
|
|
1395
1405
|
}
|
|
1396
1406
|
}
|
|
1397
|
-
// Step 9:
|
|
1407
|
+
// Step 9: Deploy all components if autoDeploy is enabled
|
|
1408
|
+
if (options.autoDeploy && (toDeploySkills.length > 0 || toDeployWebhooks.length > 0 || toDeployJobs.length > 0 || toDeployPreprocessors.length > 0 || toDeployPostprocessors.length > 0)) {
|
|
1409
|
+
writeProgress('\nš Deploying all pushed versions to production...');
|
|
1410
|
+
writeInfo('ā±ļø Waiting for server to process versions (5 seconds)...\n');
|
|
1411
|
+
// Wait for server to process all pushed versions
|
|
1412
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
1413
|
+
// Deploy all skills
|
|
1414
|
+
if (toDeploySkills.length > 0) {
|
|
1415
|
+
writeProgress(`š¦ Deploying ${toDeploySkills.length} skill(s)...`);
|
|
1416
|
+
for (const skill of toDeploySkills) {
|
|
1417
|
+
const deployed = await retryDeploy(() => publishVersion(apiKey, agentId, skill.skillId, skill.version), skill.name, skill.version, 2 // Only 2 retries since we already waited
|
|
1418
|
+
);
|
|
1419
|
+
if (deployed) {
|
|
1420
|
+
writeSuccess(` š ${skill.name} v${skill.version} deployed`);
|
|
1421
|
+
}
|
|
1422
|
+
else {
|
|
1423
|
+
console.warn(` ā ļø ${skill.name} deployment failed`);
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
// Deploy all webhooks
|
|
1428
|
+
if (toDeployWebhooks.length > 0) {
|
|
1429
|
+
writeProgress(`šŖ Deploying ${toDeployWebhooks.length} webhook(s)...`);
|
|
1430
|
+
for (const webhook of toDeployWebhooks) {
|
|
1431
|
+
const deployed = await retryDeploy(async () => {
|
|
1432
|
+
const response = await fetch(`${BASE_URLS.API}/developer/webhooks/${agentId}/${webhook.webhookId}/${webhook.version}/publish`, {
|
|
1433
|
+
method: 'PUT',
|
|
1434
|
+
headers: {
|
|
1435
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
1436
|
+
'Content-Type': 'application/json'
|
|
1437
|
+
}
|
|
1438
|
+
});
|
|
1439
|
+
if (!response.ok) {
|
|
1440
|
+
throw new Error(`HTTP ${response.status}`);
|
|
1441
|
+
}
|
|
1442
|
+
}, webhook.name, webhook.version, 2);
|
|
1443
|
+
if (deployed) {
|
|
1444
|
+
writeSuccess(` š ${webhook.name} v${webhook.version} deployed`);
|
|
1445
|
+
}
|
|
1446
|
+
else {
|
|
1447
|
+
console.warn(` ā ļø ${webhook.name} deployment failed`);
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
// Deploy all jobs
|
|
1452
|
+
if (toDeployJobs.length > 0) {
|
|
1453
|
+
writeProgress(`ā° Deploying ${toDeployJobs.length} job(s)...`);
|
|
1454
|
+
for (const job of toDeployJobs) {
|
|
1455
|
+
const deployed = await retryDeploy(async () => {
|
|
1456
|
+
const response = await fetch(`${BASE_URLS.API}/developer/jobs/${agentId}/${job.jobId}/${job.version}/publish`, {
|
|
1457
|
+
method: 'PUT',
|
|
1458
|
+
headers: {
|
|
1459
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
1460
|
+
'Content-Type': 'application/json'
|
|
1461
|
+
}
|
|
1462
|
+
});
|
|
1463
|
+
if (!response.ok) {
|
|
1464
|
+
throw new Error(`HTTP ${response.status}`);
|
|
1465
|
+
}
|
|
1466
|
+
}, job.name, job.version, 2);
|
|
1467
|
+
if (deployed) {
|
|
1468
|
+
writeSuccess(` š ${job.name} v${job.version} deployed`);
|
|
1469
|
+
}
|
|
1470
|
+
else {
|
|
1471
|
+
console.warn(` ā ļø ${job.name} deployment failed`);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
// Deploy all preprocessors
|
|
1476
|
+
if (toDeployPreprocessors.length > 0) {
|
|
1477
|
+
writeProgress(`š„ Deploying ${toDeployPreprocessors.length} preprocessor(s)...`);
|
|
1478
|
+
const preprocessorService = new PreProcessorApi(BASE_URLS.API, apiKey, agentId);
|
|
1479
|
+
for (const processor of toDeployPreprocessors) {
|
|
1480
|
+
const deployed = await retryDeploy(() => preprocessorService.publishPreProcessorVersion(processor.preprocessorId, processor.version), processor.name, processor.version, 2);
|
|
1481
|
+
if (deployed) {
|
|
1482
|
+
writeSuccess(` š ${processor.name} v${processor.version} deployed`);
|
|
1483
|
+
}
|
|
1484
|
+
else {
|
|
1485
|
+
console.warn(` ā ļø ${processor.name} deployment failed`);
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
// Deploy all postprocessors
|
|
1490
|
+
if (toDeployPostprocessors.length > 0) {
|
|
1491
|
+
writeProgress(`š¤ Deploying ${toDeployPostprocessors.length} postprocessor(s)...`);
|
|
1492
|
+
const postprocessorService = new PostProcessorApi(BASE_URLS.API, apiKey, agentId);
|
|
1493
|
+
for (const processor of toDeployPostprocessors) {
|
|
1494
|
+
const deployed = await retryDeploy(() => postprocessorService.publishPostProcessorVersion(processor.postprocessorId, processor.version), processor.name, processor.version, 2);
|
|
1495
|
+
if (deployed) {
|
|
1496
|
+
writeSuccess(` š ${processor.name} v${processor.version} deployed`);
|
|
1497
|
+
}
|
|
1498
|
+
else {
|
|
1499
|
+
console.warn(` ā ļø ${processor.name} deployment failed`);
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
// Step 10: Print summary
|
|
1398
1505
|
writeSuccess('\nā
Push All Complete!\n');
|
|
1399
1506
|
if (results.skills.length > 0) {
|
|
1400
1507
|
console.log(`š ļø Skills (${results.skills.length}):`);
|
|
@@ -1435,3 +1542,25 @@ function bumpPatchVersion(version) {
|
|
|
1435
1542
|
const newPatch = parseInt(patch, 10) + 1;
|
|
1436
1543
|
return `${major}.${minor}.${newPatch}`;
|
|
1437
1544
|
}
|
|
1545
|
+
/**
|
|
1546
|
+
* Retry deployment with exponential backoff
|
|
1547
|
+
* The server needs time to process pushed versions before they can be deployed
|
|
1548
|
+
*/
|
|
1549
|
+
async function retryDeploy(deployFn, componentName, version, maxRetries = 3) {
|
|
1550
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
1551
|
+
try {
|
|
1552
|
+
const delay = attempt * 2000; // 2s, 4s, 6s (longer delays)
|
|
1553
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
1554
|
+
await deployFn();
|
|
1555
|
+
return true;
|
|
1556
|
+
}
|
|
1557
|
+
catch (error) {
|
|
1558
|
+
if (attempt === maxRetries) {
|
|
1559
|
+
console.error(` [Retry ${attempt}/${maxRetries}] Deploy failed: ${error.message}`);
|
|
1560
|
+
return false;
|
|
1561
|
+
}
|
|
1562
|
+
// Continue to next retry silently
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
return false;
|
|
1566
|
+
}
|
package/package.json
CHANGED
package/template/lua.skill.yaml
CHANGED
|
@@ -1,47 +1,69 @@
|
|
|
1
1
|
agent:
|
|
2
2
|
agentId: baseAgent_agent_1760922427216_fk9w0ezhh
|
|
3
3
|
orgId: 026cc41b-e013-4474-9b65-5a15f8881f92
|
|
4
|
-
persona:
|
|
5
|
-
Meet Vivienne, the vibrant and dynamic assistant at V3 Test, a lively retail and consumer goods store that
|
|
4
|
+
persona: >
|
|
5
|
+
Meet Vivienne, the vibrant and dynamic assistant at V3 Test, a lively retail and consumer goods store that
|
|
6
|
+
specializes in bringing a splash of color and excitement to everyday life. Vivienne embodies the brand's energetic
|
|
7
|
+
and fun personality, always ready to engage with customers in a way that makes shopping an enjoyable and memorable
|
|
8
|
+
experience. Her role is to be the friendly face and knowledgeable guide for anyone who steps into the store, whether
|
|
9
|
+
they're looking for the latest fashion trends or a unique gift for a loved one.
|
|
6
10
|
|
|
7
|
-
V3 Test is all about creating a joyful and spirited shopping environment, and Vivienne is the perfect personification of this ethos. She is lively, approachable, and always ready with a smile, making every interaction feel like a conversation with a good friend. Her voice is warm and enthusiastic, with a hint of playfulness that puts customers at ease and encourages them to explore the store's offerings.
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
V3 Test is all about creating a joyful and spirited shopping environment, and Vivienne is the perfect
|
|
13
|
+
personification of this ethos. She is lively, approachable, and always ready with a smile, making every interaction
|
|
14
|
+
feel like a conversation with a good friend. Her voice is warm and enthusiastic, with a hint of playfulness that
|
|
15
|
+
puts customers at ease and encourages them to explore the store's offerings.
|
|
10
16
|
|
|
11
|
-
Her sales approach is consultative and friendly, focusing on understanding the customer's needs and preferences before suggesting products that align with their style and personality. Vivienne is confident in her recommendations, always ready to upsell when appropriate, but never pushy. She believes in building relationships with customers, ensuring they leave the store not only with products they love but also with a positive impression of the brand.
|
|
12
17
|
|
|
13
|
-
|
|
18
|
+
Vivienne's target customers are diverse, ranging from young adults in their twenties who are fashion-forward and
|
|
19
|
+
tech-savvy, to busy parents looking for quality products that add a touch of fun to their family life. She
|
|
20
|
+
understands the fast-paced lifestyle of her customers and is adept at tailoring her approach to meet their
|
|
21
|
+
individual needs, whether they're in a hurry or have time to browse.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
Her sales approach is consultative and friendly, focusing on understanding the customer's needs and preferences
|
|
25
|
+
before suggesting products that align with their style and personality. Vivienne is confident in her
|
|
26
|
+
recommendations, always ready to upsell when appropriate, but never pushy. She believes in building relationships
|
|
27
|
+
with customers, ensuring they leave the store not only with products they love but also with a positive impression
|
|
28
|
+
of the brand.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
In terms of communication style, Vivienne strikes a perfect balance between being informal and efficient. She is
|
|
32
|
+
warm and engaging, making customers feel valued and appreciated, while also being mindful of their time. Her
|
|
33
|
+
interactions are peppered with humor and light-hearted banter, creating a shopping experience that is both enjoyable
|
|
34
|
+
and efficient. Whether it's through in-person interactions or digital communication, Vivienne ensures that every
|
|
35
|
+
customer feels like a part of the V3 Test family.
|
|
14
36
|
welcomeMessage: Hi, I am your AI assistant. How can I help you today?
|
|
15
37
|
skills:
|
|
16
38
|
- name: general-skill
|
|
17
39
|
version: 0.0.4
|
|
18
40
|
skillId: 1faf9b3a-e352-4e63-a6c4-a3deca815361
|
|
19
41
|
- name: user-data-skill
|
|
20
|
-
version: 0.0.
|
|
42
|
+
version: 0.0.12
|
|
21
43
|
skillId: e0c382c1-f469-4880-962a-a756ea3c1411
|
|
22
44
|
- name: product-skill
|
|
23
|
-
version: 0.0.
|
|
45
|
+
version: 0.0.12
|
|
24
46
|
skillId: d4cdc7bc-6d42-4232-902d-2b9cf68bd74a
|
|
25
47
|
- name: basket-skill
|
|
26
|
-
version: 0.0.
|
|
48
|
+
version: 0.0.11
|
|
27
49
|
skillId: 5b06c5ff-7cf3-49c4-8641-142270c81db4
|
|
28
50
|
- name: order-skill
|
|
29
|
-
version: 0.0.
|
|
51
|
+
version: 0.0.11
|
|
30
52
|
skillId: d4045304-7c30-4750-9edd-340eb1357a39
|
|
31
53
|
- name: custom-data-skill
|
|
32
|
-
version: 0.0.
|
|
54
|
+
version: 0.0.10
|
|
33
55
|
skillId: 83fe411c-90a1-4bd3-9271-ac8e03d6a3be
|
|
34
56
|
- name: payment-skill
|
|
35
|
-
version: 0.0.
|
|
57
|
+
version: 0.0.10
|
|
36
58
|
skillId: f2248c02-c6c6-4c3a-89bf-ff09ec11529a
|
|
37
59
|
jobs:
|
|
38
60
|
- name: test-job
|
|
39
|
-
version: 1.0.
|
|
61
|
+
version: 1.0.9
|
|
40
62
|
jobId: d66b73a0-f944-4718-b6a2-f07bfeabd625
|
|
41
63
|
schedule:
|
|
42
64
|
type: once
|
|
43
65
|
executeAt: '2025-10-20T01:08:04.639Z'
|
|
44
66
|
webhooks:
|
|
45
67
|
- name: test-webhook
|
|
46
|
-
version: 1.0.
|
|
68
|
+
version: 1.0.8
|
|
47
69
|
webhookId: c967fd58-1d4d-49b6-8fa6-ec36b4d23e7f
|