lua-cli 3.0.2 → 3.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -83,7 +83,9 @@ export default class JobApi extends HttpClient {
83
83
  * @returns Promise resolving to an ApiResponse containing an array of jobs with their versions
84
84
  * @throws Error if the API request fails or the agent is not found
85
85
  */
86
- getJobs(): Promise<ApiResponse<GetJobsResponse>>;
86
+ getJobs(options?: {
87
+ includeDynamic?: boolean;
88
+ }): Promise<ApiResponse<GetJobsResponse>>;
87
89
  /**
88
90
  * Retrieves a job by its unique identifier
89
91
  * @param jobId - The unique identifier of the job to retrieve
@@ -22,8 +22,13 @@ export default class JobApi extends HttpClient {
22
22
  * @returns Promise resolving to an ApiResponse containing an array of jobs with their versions
23
23
  * @throws Error if the API request fails or the agent is not found
24
24
  */
25
- async getJobs() {
26
- return this.httpGet(`/developer/jobs/${this.agentId}`, {
25
+ async getJobs(options = {}) {
26
+ const queryParams = new URLSearchParams();
27
+ if (options.includeDynamic) {
28
+ queryParams.append('includeDynamic', 'true');
29
+ }
30
+ const url = `/developer/jobs/${this.agentId}?${queryParams.toString()}`;
31
+ return this.httpGet(url, {
27
32
  Authorization: `Bearer ${this.apiKey}`,
28
33
  });
29
34
  }
@@ -15,21 +15,19 @@ export default class LogsApi extends HttpClient {
15
15
  constructor(baseUrl: string, apiKey: string);
16
16
  /**
17
17
  * Retrieves logs for an agent
18
- * @param agentId - The unique identifier of the agent
18
+ * @param agentId - The ID of the agent
19
19
  * @param limit - Number of logs per page (default: 20)
20
20
  * @param page - Page number (default: 1)
21
+ * @param skillId - Optional skill ID to filter logs
22
+ * @param logType - Optional log type to filter logs
21
23
  * @returns Promise resolving to an ApiResponse containing logs and pagination
22
- * @throws Error if the API request fails
23
24
  */
24
- getAgentLogs(agentId: string, limit?: number, page?: number): Promise<ApiResponse<LogsResponse>>;
25
- /**
26
- * Retrieves logs for a specific skill
27
- * @param agentId - The unique identifier of the agent
28
- * @param skillId - The unique identifier of the skill
29
- * @param limit - Number of logs per page (default: 20)
30
- * @param page - Page number (default: 1)
31
- * @returns Promise resolving to an ApiResponse containing logs and pagination
32
- * @throws Error if the API request fails
33
- */
34
- getSkillLogs(agentId: string, skillId: string, limit?: number, page?: number): Promise<ApiResponse<LogsResponse>>;
25
+ getAgentLogs(agentId: string, limit: number, page: number, filters?: {
26
+ primitiveType?: "skill" | "job" | "webhook" | "preprocessor" | "postprocessor";
27
+ primitiveId?: string;
28
+ primitiveName?: string;
29
+ toolId?: string;
30
+ toolName?: string;
31
+ logType?: string;
32
+ }): Promise<ApiResponse<LogsResponse>>;
35
33
  }
@@ -15,28 +15,31 @@ export default class LogsApi extends HttpClient {
15
15
  }
16
16
  /**
17
17
  * Retrieves logs for an agent
18
- * @param agentId - The unique identifier of the agent
18
+ * @param agentId - The ID of the agent
19
19
  * @param limit - Number of logs per page (default: 20)
20
20
  * @param page - Page number (default: 1)
21
+ * @param skillId - Optional skill ID to filter logs
22
+ * @param logType - Optional log type to filter logs
21
23
  * @returns Promise resolving to an ApiResponse containing logs and pagination
22
- * @throws Error if the API request fails
23
24
  */
24
- async getAgentLogs(agentId, limit = 20, page = 1) {
25
- return this.httpGet(`/developer/agents/${agentId}/logs?limit=${limit}&page=${page}`, {
26
- Authorization: `Bearer ${this.apiKey}`,
25
+ async getAgentLogs(agentId, limit, page, filters = {}) {
26
+ const queryParams = new URLSearchParams({
27
+ limit: limit.toString(),
28
+ page: page.toString(),
27
29
  });
28
- }
29
- /**
30
- * Retrieves logs for a specific skill
31
- * @param agentId - The unique identifier of the agent
32
- * @param skillId - The unique identifier of the skill
33
- * @param limit - Number of logs per page (default: 20)
34
- * @param page - Page number (default: 1)
35
- * @returns Promise resolving to an ApiResponse containing logs and pagination
36
- * @throws Error if the API request fails
37
- */
38
- async getSkillLogs(agentId, skillId, limit = 20, page = 1) {
39
- return this.httpGet(`/developer/skills/${agentId}/${skillId}/logs?limit=${limit}&page=${page}`, {
30
+ if (filters.primitiveType)
31
+ queryParams.append("primitiveType", filters.primitiveType);
32
+ if (filters.primitiveId)
33
+ queryParams.append("primitiveId", filters.primitiveId);
34
+ if (filters.primitiveName)
35
+ queryParams.append("primitiveName", filters.primitiveName);
36
+ if (filters.toolId)
37
+ queryParams.append("toolId", filters.toolId);
38
+ if (filters.toolName)
39
+ queryParams.append("toolName", filters.toolName);
40
+ if (filters.logType)
41
+ queryParams.append("logType", filters.logType);
42
+ return this.httpGet(`/developer/agents/${agentId}/logs?${queryParams.toString()}`, {
40
43
  Authorization: `Bearer ${this.apiKey}`,
41
44
  });
42
45
  }
@@ -18,7 +18,7 @@ export default class UserDataApi extends HttpClient implements UserDataAPI {
18
18
  * @returns Promise resolving to a UserDataInstance containing the user's data
19
19
  * @throws Error if the user data cannot be retrieved or the request fails
20
20
  */
21
- get(): Promise<UserDataInstance>;
21
+ get(userId?: string): Promise<UserDataInstance>;
22
22
  /**
23
23
  * Updates the current user's data for the specific agent
24
24
  * @param data - The data object containing fields to update or add to user data
@@ -18,14 +18,21 @@ export default class UserDataApi extends HttpClient {
18
18
  * @returns Promise resolving to a UserDataInstance containing the user's data
19
19
  * @throws Error if the user data cannot be retrieved or the request fails
20
20
  */
21
- async get() {
22
- const response = await this.httpGet(`/developer/user/data/agent/${this.agentId}`, {
21
+ async get(userId) {
22
+ let url = `/developer/user/data/agent/${this.agentId}`;
23
+ if (userId) {
24
+ url += `/user/${userId}`;
25
+ }
26
+ const response = await this.httpGet(url, {
23
27
  Authorization: `Bearer ${this.apiKey}`,
24
28
  });
25
29
  if (!response.success) {
26
30
  throw new Error(response.error?.message || 'Failed to get user data');
27
31
  }
28
- return new UserDataInstance(this, response.data);
32
+ // Extract profile data and remove from response
33
+ const profile = response.data?._luaProfile;
34
+ const { _luaProfile, ...data } = response.data || {};
35
+ return new UserDataInstance(this, data, profile);
29
36
  }
30
37
  /**
31
38
  * Updates the current user's data for the specific agent
@@ -40,7 +47,9 @@ export default class UserDataApi extends HttpClient {
40
47
  if (!response.success) {
41
48
  throw new Error(response.error?.message || 'Failed to update user data');
42
49
  }
43
- return response.data;
50
+ // Extract profile if present and remove from response
51
+ const { _luaProfile, ...cleanData } = response.data || {};
52
+ return cleanData;
44
53
  }
45
54
  /**
46
55
  * Clears all user data for the current user and specific agent
@@ -46,7 +46,7 @@ export declare const User: {
46
46
  *
47
47
  * @returns Promise resolving to user data
48
48
  */
49
- get(): Promise<UserDataInstance>;
49
+ get(userId?: string): Promise<UserDataInstance>;
50
50
  /**
51
51
  * Gets the chat history for the current user.
52
52
  *
@@ -42,9 +42,9 @@ export const User = {
42
42
  *
43
43
  * @returns Promise resolving to user data
44
44
  */
45
- async get() {
45
+ async get(userId) {
46
46
  const instance = await getUserInstance();
47
- return instance.get();
47
+ return instance.get(userId);
48
48
  },
49
49
  /**
50
50
  * Gets the chat history for the current user.
@@ -9,6 +9,11 @@ import { readSkillConfig } from "../utils/files.js";
9
9
  import { withErrorHandling, writeSuccess, writeInfo, writeError, clearPromptLines } from "../utils/cli.js";
10
10
  import LogsApi from '../api/logs.api.service.js';
11
11
  import { BASE_URLS } from '../config/constants.js';
12
+ import SkillApi from "../api/skills.api.service.js";
13
+ import JobApi from "../api/job.api.service.js";
14
+ import WebhookApi from "../api/webhook.api.service.js";
15
+ import PreprocessorApi from "../api/preprocessor.api.service.js";
16
+ import PostprocessorApi from "../api/postprocessor.api.service.js";
12
17
  /**
13
18
  * Main logs command - displays agent/skill logs with navigation
14
19
  *
@@ -45,102 +50,147 @@ export async function logsCommand() {
45
50
  message: "What logs do you want to view?",
46
51
  choices: [
47
52
  { name: "📋 All agent logs", value: "all" },
48
- { name: "🎯 Specific skill logs", value: "skill" }
49
- ]
50
- }
53
+ { name: "🔎 Filter logs", value: "filter" },
54
+ ],
55
+ },
51
56
  ]);
52
57
  clearPromptLines(2);
53
58
  if (viewType === "all") {
54
59
  await viewAgentLogs(logsApi, agentId);
55
60
  }
56
61
  else {
57
- await viewSkillLogs(logsApi, agentId, config);
62
+ await filterAndShowLogs(logsApi, agentId, apiKey);
58
63
  }
59
64
  }, "logs viewing");
60
65
  }
61
- /**
62
- * View all logs for an agent with pagination
63
- */
64
- async function viewAgentLogs(logsApi, agentId) {
65
- let currentPage = 1;
66
- const limit = 20;
67
- let keepViewing = true;
68
- while (keepViewing) {
69
- const response = await logsApi.getAgentLogs(agentId, limit, currentPage);
70
- if (!response.success) {
71
- writeError(`❌ Error: ${response.error?.message || 'Unknown error'}`);
72
- process.exit(1);
66
+ async function filterAndShowLogs(logsApi, agentId, apiKey) {
67
+ const apiServices = {
68
+ skill: new SkillApi(BASE_URLS.API, apiKey, agentId),
69
+ job: new JobApi(BASE_URLS.API, apiKey, agentId),
70
+ webhook: new WebhookApi(BASE_URLS.API, apiKey, agentId),
71
+ preprocessor: new PreprocessorApi(BASE_URLS.API, apiKey, agentId),
72
+ postprocessor: new PostprocessorApi(BASE_URLS.API, apiKey, agentId),
73
+ };
74
+ let keepFiltering = true;
75
+ while (keepFiltering) {
76
+ const { filterType } = await inquirer.prompt([
77
+ {
78
+ type: "list",
79
+ name: "filterType",
80
+ message: "Filter by:",
81
+ choices: [
82
+ { name: "📋 All logs", value: "all" },
83
+ new inquirer.Separator(),
84
+ { name: "Skills", value: "skill" },
85
+ { name: "Jobs", value: "job" },
86
+ { name: "Webhooks", value: "webhook" },
87
+ { name: "Preprocessors", value: "preprocessor" },
88
+ { name: "Postprocessors", value: "postprocessor" },
89
+ new inquirer.Separator(),
90
+ { name: "← Back", value: "back" },
91
+ new inquirer.Separator(),
92
+ ],
93
+ },
94
+ ]);
95
+ if (filterType === "all") {
96
+ await viewAgentLogs(logsApi, agentId);
97
+ return; // Exit to main command menu
73
98
  }
74
- const data = response.data;
75
- displayLogs(data.logs, data.pagination, "All Agent Logs");
76
- // Navigation menu
77
- const { action } = await inquirer.prompt([
99
+ if (filterType === "back") {
100
+ await logsCommand();
101
+ return; // Exit to main command menu
102
+ }
103
+ const primitiveType = filterType;
104
+ const capitalizedType = primitiveType.charAt(0).toUpperCase() + primitiveType.slice(1);
105
+ let response;
106
+ let items = [];
107
+ switch (primitiveType) {
108
+ case "skill":
109
+ response = await apiServices.skill.getSkills();
110
+ items = response.data?.skills || [];
111
+ break;
112
+ case "job":
113
+ response = await apiServices.job.getJobs({ includeDynamic: true });
114
+ items = response.data?.jobs || [];
115
+ break;
116
+ case "webhook":
117
+ response = await apiServices.webhook.getWebhooks();
118
+ items = response.data?.webhooks || [];
119
+ break;
120
+ case "preprocessor":
121
+ response = await apiServices.preprocessor.getPreProcessors();
122
+ items = response.data?.preprocessors || [];
123
+ break;
124
+ case "postprocessor":
125
+ response = await apiServices.postprocessor.getPostProcessors();
126
+ items = response.data?.postprocessors || [];
127
+ break;
128
+ default:
129
+ writeError("❌ Invalid filter type selected.");
130
+ continue;
131
+ }
132
+ if (!response || !response.success || !response.data) {
133
+ writeError(`❌ Could not fetch ${primitiveType}s from the API.`);
134
+ continue;
135
+ }
136
+ if (items.length === 0) {
137
+ writeInfo(`ℹ️ No ${primitiveType}s found for this agent.\n`);
138
+ continue;
139
+ }
140
+ const { selectedId } = await inquirer.prompt([
78
141
  {
79
142
  type: "list",
80
- name: "action",
81
- message: "Navigation:",
82
- choices: getNavigationChoices(data.pagination)
83
- }
143
+ name: "selectedId",
144
+ message: `Select a ${primitiveType}:`,
145
+ choices: [
146
+ { name: `All ${capitalizedType}s`, value: "all" },
147
+ new inquirer.Separator(),
148
+ ...items.map((item) => ({
149
+ name: item.name,
150
+ value: item.id,
151
+ })),
152
+ new inquirer.Separator(),
153
+ { name: "← Back", value: "back" },
154
+ new inquirer.Separator(),
155
+ ],
156
+ },
84
157
  ]);
85
- clearPromptLines(2);
86
- keepViewing = await handleNavigation(action, data.pagination, (page) => {
87
- currentPage = page;
88
- });
158
+ if (selectedId === "back") {
159
+ continue;
160
+ }
161
+ const filters = {
162
+ primitiveType,
163
+ };
164
+ if (selectedId !== "all") {
165
+ filters.primitiveId = selectedId;
166
+ }
167
+ await viewAgentLogs(logsApi, agentId, filters);
168
+ return;
89
169
  }
90
170
  }
91
171
  /**
92
- * View logs for a specific skill with pagination
172
+ * View all logs for an agent with pagination
93
173
  */
94
- async function viewSkillLogs(logsApi, agentId, config) {
95
- // Get skills from config
96
- const skills = config?.skills || [];
97
- if (skills.length === 0) {
98
- writeError("❌ No skills found in lua.skill.yaml");
99
- writeInfo("💡 Run 'lua push' to deploy skills first.\n");
100
- return;
101
- }
102
- // Let user select a skill
103
- const skillChoices = skills.map((skill) => ({
104
- name: `${skill.name} (${skill.skillId || 'No ID'})`,
105
- value: skill.skillId
106
- }));
107
- skillChoices.push({
108
- name: '← Back to main menu',
109
- value: null
110
- });
111
- const { skillId } = await inquirer.prompt([
112
- {
113
- type: "list",
114
- name: "skillId",
115
- message: "Select a skill:",
116
- choices: skillChoices
117
- }
118
- ]);
119
- if (!skillId) {
120
- return;
121
- }
122
- clearPromptLines(2);
174
+ async function viewAgentLogs(logsApi, agentId, filters = {}) {
123
175
  let currentPage = 1;
124
176
  const limit = 20;
125
177
  let keepViewing = true;
126
- const selectedSkill = skills.find((s) => s.skillId === skillId);
127
- const skillName = selectedSkill?.name || skillId;
128
178
  while (keepViewing) {
129
- const response = await logsApi.getSkillLogs(agentId, skillId, limit, currentPage);
179
+ const response = await logsApi.getAgentLogs(agentId, limit, currentPage, filters);
130
180
  if (!response.success) {
131
181
  writeError(`❌ Error: ${response.error?.message || 'Unknown error'}`);
132
182
  process.exit(1);
133
183
  }
134
184
  const data = response.data;
135
- displayLogs(data.logs, data.pagination, `Logs for ${skillName}`);
185
+ displayLogs(data.logs, data.pagination, "All Agent Logs");
136
186
  // Navigation menu
137
187
  const { action } = await inquirer.prompt([
138
188
  {
139
189
  type: "list",
140
190
  name: "action",
141
191
  message: "Navigation:",
142
- choices: getNavigationChoices(data.pagination)
143
- }
192
+ choices: getNavigationChoices(data.pagination),
193
+ },
144
194
  ]);
145
195
  clearPromptLines(2);
146
196
  keepViewing = await handleNavigation(action, data.pagination, (page) => {
@@ -167,11 +217,21 @@ function displayLogs(logs, pagination, title) {
167
217
  const icon = getLogIcon(log.subType);
168
218
  const color = getLogColor(log.subType);
169
219
  console.log(color(`${icon} [${timestamp}] ${log.subType.toUpperCase()}`));
170
- if (log.metadata.skillName) {
171
- console.log(chalk.gray(` Skill: ${log.metadata.skillName}`));
220
+ const { primitiveType, primitiveId, primitiveName, toolName, toolId } = log.metadata;
221
+ const capitalizedType = primitiveType
222
+ ? primitiveType.charAt(0).toUpperCase() + primitiveType.slice(1)
223
+ : "Item";
224
+ if (primitiveName) {
225
+ console.log(chalk.gray(` ${capitalizedType} Name: ${primitiveName}`));
172
226
  }
173
- if (log.metadata.toolId) {
174
- console.log(chalk.gray(` Tool: ${log.metadata.toolId}`));
227
+ if (primitiveId) {
228
+ console.log(chalk.gray(` ${capitalizedType} ID: ${primitiveId}`));
229
+ }
230
+ // Only show tool information for skills
231
+ if (primitiveType === "skill") {
232
+ if (toolName) {
233
+ console.log(chalk.gray(` Tool Name: ${toolName}`));
234
+ }
175
235
  }
176
236
  if (log.duration !== undefined) {
177
237
  console.log(chalk.gray(` Duration: ${log.duration}ms`));
@@ -388,9 +388,11 @@ async function listPersonaVersions(context) {
388
388
  choices: sortedVersions.map((version, index) => {
389
389
  const date = new Date(version.createdDate);
390
390
  const dateStr = date.toLocaleDateString();
391
- const deployedMark = version.isCurrent ? ' ⭐ CURRENT' : '';
391
+ const timeStr = date.toLocaleTimeString();
392
+ const status = version.status === 'draft' ? '[DRAFT]' : '';
393
+ const currentMark = version.isCurrent ? ' ⭐ CURRENT' : '';
392
394
  return {
393
- name: `Version ${version.version} (${dateStr})${deployedMark}`,
395
+ name: `Version ${version.version} ${status} - (${dateStr}) ${timeStr} ${currentMark}`,
394
396
  value: index
395
397
  };
396
398
  })
@@ -415,7 +417,9 @@ async function viewVersionDetails(versions) {
415
417
  console.log(`Persona Version ${version.version}`);
416
418
  console.log("=".repeat(60));
417
419
  console.log(`Created: ${date.toLocaleString()}`);
418
- console.log(`Status: ${version.isCurrent ? ' CURRENT' : 'Available'}`);
420
+ const versionStatus = version.status === 'draft' ? '🔨 DRAFT' : '';
421
+ console.log(`Version Status: ${versionStatus}`);
422
+ console.log(`Active Status: ${version.isCurrent ? '⭐ CURRENT' : 'Available'}`);
419
423
  if (version.createdBy) {
420
424
  console.log(`Created by: ${version.createdBy}`);
421
425
  }
@@ -480,8 +484,9 @@ async function deployPersonaVersion(context) {
480
484
  const dateStr = date.toLocaleDateString();
481
485
  const timeStr = date.toLocaleTimeString();
482
486
  const currentMark = v.isCurrent ? ' ⭐ CURRENTLY DEPLOYED' : '';
487
+ const status = v.status === "draft" ? "[DRAFT]" : "";
483
488
  return {
484
- name: `Version ${v.version} - ${dateStr} ${timeStr}${currentMark}`,
489
+ name: `Version ${v.version} ${status} - (${dateStr}) ${timeStr} ${currentMark}`,
485
490
  value: v.version
486
491
  };
487
492
  })
@@ -2,7 +2,6 @@
2
2
  * Job Instance
3
3
  * Provides a convenient interface for interacting with a job
4
4
  */
5
- import UserDataInstance from './user.instance.js';
6
5
  import UserDataApi from '../api/user.data.api.service.js';
7
6
  import { BASE_URLS } from '../config/constants.js';
8
7
  /**
@@ -97,8 +96,7 @@ export class JobInstance {
97
96
  }
98
97
  }
99
98
  async user() {
100
- const result = await this.userApi.get();
101
- return new UserDataInstance(this.userApi, result);
99
+ return await this.userApi.get();
102
100
  }
103
101
  /**
104
102
  * Converts the job instance to JSON.
@@ -1,21 +1,24 @@
1
1
  import { Message } from "../interfaces/message.js";
2
2
  import { UserDataAPI } from "../types/index.js";
3
+ import { ImmutableUserProfile, UserAgentData } from "../interfaces/user.js";
3
4
  /**
4
5
  * User data instance class providing a fluent API for managing user data
5
6
  * Provides methods for updating and clearing data
6
7
  * Supports direct property access (e.g., user.name) instead of user.data.name
7
8
  */
8
9
  export default class UserDataInstance {
9
- data: Record<string, any>;
10
+ data: UserAgentData;
10
11
  private userAPI;
12
+ _luaProfile: ImmutableUserProfile;
11
13
  [key: string]: any;
12
14
  /**
13
15
  * Creates a new UserDataInstance with proxy support for direct property access
14
16
  * @param api - The UserDataAPI instance for making API calls
15
17
  * @param data - The user data from the API
18
+ * @param profile - The immutable user profile data
16
19
  * @returns Proxied instance that allows direct access to data properties
17
20
  */
18
- constructor(api: UserDataAPI, data: any);
21
+ constructor(api: UserDataAPI, data: any, profile?: ImmutableUserProfile);
19
22
  /**
20
23
  * Custom toJSON method to control what gets serialized when logging
21
24
  * @returns Serialized user data