@nestbox-ai/cli 1.0.13 → 1.0.16
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/.nestboxrc +5 -0
- package/dist/commands/agent.js +592 -173
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/auth.js +1 -0
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/compute.js +38 -8
- package/dist/commands/compute.js.map +1 -1
- package/dist/commands/document.js +2 -0
- package/dist/commands/document.js.map +1 -1
- package/dist/commands/image.js +107 -110
- package/dist/commands/image.js.map +1 -1
- package/dist/commands/projects.js +118 -30
- package/dist/commands/projects.js.map +1 -1
- package/dist/types/agentType.d.ts +1 -1
- package/dist/types/agentType.js +1 -1
- package/dist/types/agentType.js.map +1 -1
- package/dist/types/agentYaml.d.ts +91 -0
- package/dist/types/agentYaml.js +6 -0
- package/dist/types/agentYaml.js.map +1 -0
- package/dist/types/auth.d.ts +4 -6
- package/dist/types/auth.js +1 -0
- package/dist/types/auth.js.map +1 -1
- package/dist/utils/agent.d.ts +11 -0
- package/dist/utils/agent.js +72 -0
- package/dist/utils/agent.js.map +1 -1
- package/dist/utils/auth.d.ts +4 -0
- package/dist/utils/auth.js +31 -3
- package/dist/utils/auth.js.map +1 -1
- package/dist/utils/error.d.ts +8 -0
- package/dist/utils/error.js +163 -0
- package/dist/utils/error.js.map +1 -0
- package/dist/utils/project.d.ts +4 -1
- package/dist/utils/project.js +17 -10
- package/dist/utils/project.js.map +1 -1
- package/package.json +3 -1
- package/sample-agents.yaml +0 -0
- package/src/commands/agent.ts +770 -303
- package/src/commands/auth.ts +1 -0
- package/src/commands/compute.ts +30 -8
- package/src/commands/document.ts +2 -2
- package/src/commands/image.ts +121 -129
- package/src/commands/projects.ts +125 -34
- package/src/types/agentType.ts +1 -1
- package/src/types/agentYaml.ts +107 -0
- package/src/types/auth.ts +10 -10
- package/src/utils/agent.ts +82 -0
- package/src/utils/auth.ts +33 -3
- package/src/utils/error.ts +168 -0
- package/src/utils/project.ts +20 -13
- package/templates/template-base-js.zip +0 -0
- package/templates/template-base-ts.zip +0 -0
- package/templates/template-chatbot-js.zip +0 -0
- package/templates/template-chatbot-ts.zip +0 -0
package/src/commands/agent.ts
CHANGED
|
@@ -1,35 +1,159 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
+
import { handle401Error, withTokenRefresh } from "../utils/error";
|
|
2
3
|
import chalk from "chalk";
|
|
3
4
|
import ora from "ora";
|
|
4
5
|
import Table from "cli-table3";
|
|
5
6
|
import { getAuthToken } from "../utils/auth";
|
|
6
|
-
import { Configuration, MachineAgentApi, ProjectsApi } from "@nestbox-ai/admin";
|
|
7
|
+
import { Configuration, MachineAgentApi, MachineInstancesApi, ProjectsApi } from "@nestbox-ai/admin";
|
|
7
8
|
import { resolveProject } from "../utils/project";
|
|
8
9
|
import fs from "fs";
|
|
10
|
+
import yaml from 'js-yaml';
|
|
9
11
|
import {
|
|
12
|
+
createNestboxConfig,
|
|
10
13
|
createZipFromDirectory,
|
|
14
|
+
downloadFromGoogleDrive,
|
|
15
|
+
extractZip,
|
|
11
16
|
findProjectRoot,
|
|
12
17
|
isTypeScriptProject,
|
|
13
18
|
loadNestboxConfig,
|
|
14
19
|
runPredeployScripts,
|
|
20
|
+
TEMPLATES,
|
|
15
21
|
} from "../utils/agent";
|
|
16
22
|
import axios from "axios";
|
|
17
23
|
import { AgentType } from "../types/agentType";
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
import { AgentYamlConfig } from "../types/agentYaml";
|
|
25
|
+
import inquirer from "inquirer";
|
|
26
|
+
import path from "path";
|
|
27
|
+
import { userData } from "../utils/user";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Create a new agent in the Nestbox platform
|
|
31
|
+
*
|
|
32
|
+
* @param agentName The name of the agent
|
|
33
|
+
* @param options Options including lang, template, and project
|
|
34
|
+
* @param agentsApi The MachineAgentApi instance
|
|
35
|
+
* @param projectsApi The ProjectsApi instance
|
|
36
|
+
*/
|
|
37
|
+
async function createAgent(
|
|
38
|
+
agentName: string,
|
|
39
|
+
options: {
|
|
40
|
+
lang?: string;
|
|
41
|
+
template?: string;
|
|
42
|
+
project?: string;
|
|
43
|
+
instanceName?: string;
|
|
44
|
+
machineManifestId?: string;
|
|
45
|
+
type?: string;
|
|
46
|
+
goal?: string;
|
|
47
|
+
modelBaseId?: string;
|
|
48
|
+
machineName?: string;
|
|
49
|
+
machineInstanceId?: number;
|
|
50
|
+
instanceIP?: string;
|
|
51
|
+
userId?: number;
|
|
52
|
+
parameters?: Array<{name: string; description: string; default: any}>;
|
|
53
|
+
},
|
|
54
|
+
agentsApi?: MachineAgentApi,
|
|
55
|
+
projectsApi?: ProjectsApi
|
|
56
|
+
): Promise<any> {
|
|
21
57
|
const authToken = getAuthToken();
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
58
|
+
if (!authToken) {
|
|
59
|
+
throw new Error("No authentication token found. Please login first.");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Create API instances if not provided
|
|
63
|
+
if (!agentsApi || !projectsApi) {
|
|
64
|
+
const configuration = new Configuration({
|
|
65
|
+
basePath: authToken?.serverUrl,
|
|
66
|
+
baseOptions: {
|
|
67
|
+
headers: {
|
|
68
|
+
Authorization: authToken?.token,
|
|
69
|
+
},
|
|
27
70
|
},
|
|
28
|
-
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
agentsApi = agentsApi || new MachineAgentApi(configuration);
|
|
74
|
+
projectsApi = projectsApi || new ProjectsApi(configuration);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Resolve project - convert options to match CommandOptions interface
|
|
78
|
+
const projectData = await resolveProject(projectsApi, {
|
|
79
|
+
project: options.project,
|
|
80
|
+
instance: options.instanceName || '',
|
|
81
|
+
...options
|
|
29
82
|
});
|
|
30
83
|
|
|
31
|
-
|
|
32
|
-
|
|
84
|
+
// Prepare agent creation payload
|
|
85
|
+
// Determine the correct type value based on options.type
|
|
86
|
+
const agentTypeValue = options.type?.includes("AGENT") ? "REGULAR" : options.type || "CHAT";
|
|
87
|
+
|
|
88
|
+
const payload: any = {
|
|
89
|
+
agentName,
|
|
90
|
+
goal: options.goal || `AI agent for ${agentName}`,
|
|
91
|
+
modelBaseId: options.modelBaseId || "",
|
|
92
|
+
machineName: options.machineName,
|
|
93
|
+
machineInstanceId: options.machineInstanceId,
|
|
94
|
+
instanceIP: options.instanceIP,
|
|
95
|
+
machineManifestId: options.machineManifestId,
|
|
96
|
+
parameters: options.parameters?.map((param: any) => ({
|
|
97
|
+
name: param.name,
|
|
98
|
+
description: param.description,
|
|
99
|
+
default_value: param.default || "",
|
|
100
|
+
isUserParam: param.isUserParam !== undefined ? param.isUserParam : true
|
|
101
|
+
})) || [],
|
|
102
|
+
projectId: projectData.id,
|
|
103
|
+
type: agentTypeValue,
|
|
104
|
+
userId: options.userId || 0,
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Determine the type of resource (Agent or Chat)
|
|
108
|
+
const agentType = options.type || "CHAT";
|
|
109
|
+
const resourceType = agentType === "AGENT" || agentType === "REGULAR" ? "Agent" : "Chatbot";
|
|
110
|
+
|
|
111
|
+
// Create the agent
|
|
112
|
+
const spinner = ora(`Creating ${resourceType.toLowerCase()} ${agentName}...`).start();
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const response = await agentsApi.machineAgentControllerCreateMachineAgent(
|
|
116
|
+
projectData.id,
|
|
117
|
+
payload
|
|
118
|
+
);
|
|
119
|
+
spinner.succeed(`${resourceType} '${agentName}' created successfully`);
|
|
120
|
+
return response.data;
|
|
121
|
+
} catch (error: any) {
|
|
122
|
+
spinner.fail(`Failed to create ${resourceType.toLowerCase()} ${agentName}`);
|
|
123
|
+
|
|
124
|
+
if (error.response && error.response.status === 401) {
|
|
125
|
+
throw new Error('Authentication token has expired. Please login again using "nestbox login <domain>".');
|
|
126
|
+
} else if (error.response) {
|
|
127
|
+
throw new Error(`API Error (${error.response.status}): ${error.response.data?.message || "Unknown error"}`);
|
|
128
|
+
} else {
|
|
129
|
+
throw new Error(error.message || "Unknown error");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function registerAgentCommands(program: Command): void {
|
|
135
|
+
// Function to create/recreate API instances
|
|
136
|
+
const createApis = () => {
|
|
137
|
+
const authToken = getAuthToken();
|
|
138
|
+
if (!authToken) {
|
|
139
|
+
throw new Error('No authentication token found. Please log in first.');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const configuration = new Configuration({
|
|
143
|
+
basePath: authToken.serverUrl,
|
|
144
|
+
baseOptions: {
|
|
145
|
+
headers: {
|
|
146
|
+
Authorization: authToken.token,
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
agentsApi: new MachineAgentApi(configuration),
|
|
153
|
+
projectsApi: new ProjectsApi(configuration),
|
|
154
|
+
instanceApi: new MachineInstancesApi(configuration)
|
|
155
|
+
};
|
|
156
|
+
};
|
|
33
157
|
|
|
34
158
|
// Create the main agent command
|
|
35
159
|
const agentCommand = program
|
|
@@ -46,108 +170,88 @@ export function registerAgentCommands(program: Command): void {
|
|
|
46
170
|
)
|
|
47
171
|
.action(async (options) => {
|
|
48
172
|
try {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
173
|
+
let apis = createApis();
|
|
174
|
+
|
|
175
|
+
// Execute with token refresh support
|
|
176
|
+
await withTokenRefresh(
|
|
177
|
+
async () => {
|
|
178
|
+
// Resolve project
|
|
179
|
+
const projectData = await resolveProject(apis.projectsApi, options);
|
|
180
|
+
|
|
181
|
+
const spinner = ora(
|
|
182
|
+
`Listing agents in project ${projectData.name}...`
|
|
183
|
+
).start();
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
// Get the agents for the specific project
|
|
187
|
+
const agentsResponse: any =
|
|
188
|
+
await apis.agentsApi.machineAgentControllerGetMachineAgentByProjectId(
|
|
189
|
+
projectData.id,
|
|
190
|
+
0,
|
|
191
|
+
10,
|
|
192
|
+
AgentType.REGULAR
|
|
193
|
+
);
|
|
59
194
|
|
|
60
|
-
|
|
61
|
-
`Listing agents in project ${projectData.name}...`
|
|
62
|
-
).start();
|
|
195
|
+
spinner.succeed("Successfully retrieved agents");
|
|
63
196
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const agentsResponse: any =
|
|
67
|
-
await agentsApi.machineAgentControllerGetMachineAgentByProjectId(
|
|
68
|
-
projectData.id,
|
|
69
|
-
0,
|
|
70
|
-
10,
|
|
71
|
-
AgentType.REGULAR
|
|
72
|
-
);
|
|
197
|
+
// Display the results
|
|
198
|
+
const agents = agentsResponse.data?.machineAgents || [];
|
|
73
199
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
200
|
+
if (!agents || agents.length === 0) {
|
|
201
|
+
console.log(
|
|
202
|
+
chalk.yellow(`No agents found in project ${projectData.name}`)
|
|
203
|
+
);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
78
206
|
|
|
79
|
-
if (!agents || agents.length === 0) {
|
|
80
207
|
console.log(
|
|
81
|
-
chalk.
|
|
208
|
+
chalk.blue(`\nAgents in project ${projectData.name}:\n`)
|
|
82
209
|
);
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
210
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
createdAt = new Date(createdAt).toLocaleString();
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
table.push([agent.id || "N/A", agent.agentName || "N/A", url]);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
// Display the table
|
|
122
|
-
console.log(table.toString());
|
|
123
|
-
|
|
124
|
-
// Display totals
|
|
125
|
-
console.log(`\nTotal agents: ${agents.length}`);
|
|
126
|
-
} catch (error: any) {
|
|
127
|
-
spinner.fail("Failed to retrieve agents");
|
|
128
|
-
if (error.response) {
|
|
129
|
-
console.error(
|
|
130
|
-
chalk.red("API Error:"),
|
|
131
|
-
error.response.data?.message || "Unknown error"
|
|
132
|
-
);
|
|
133
|
-
} else {
|
|
134
|
-
console.error(
|
|
135
|
-
chalk.red("Error:"),
|
|
136
|
-
error.message || "Unknown error"
|
|
137
|
-
);
|
|
211
|
+
// Create a formatted table
|
|
212
|
+
const table = new Table({
|
|
213
|
+
head: [
|
|
214
|
+
chalk.white.bold("ID"),
|
|
215
|
+
chalk.white.bold("Name"),
|
|
216
|
+
chalk.white.bold("URL"),
|
|
217
|
+
],
|
|
218
|
+
style: {
|
|
219
|
+
head: [],
|
|
220
|
+
border: [],
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Add agents to the table
|
|
225
|
+
agents.forEach((agent: any) => {
|
|
226
|
+
let url = "N/A";
|
|
227
|
+
if (agent.instanceIP) {
|
|
228
|
+
url = `${agent.instanceIP}/v1/agents/${agent.modelBaseId}/query`;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
table.push([agent.id || "N/A", agent.agentName || "N/A", url]);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
console.log(table.toString());
|
|
235
|
+
console.log(`\nTotal agents: ${agents.length}`);
|
|
236
|
+
|
|
237
|
+
} catch (error: any) {
|
|
238
|
+
spinner.fail("Failed to retrieve agents");
|
|
239
|
+
throw error;
|
|
138
240
|
}
|
|
241
|
+
},
|
|
242
|
+
() => {
|
|
243
|
+
// Recreate APIs after token refresh
|
|
244
|
+
apis = createApis();
|
|
139
245
|
}
|
|
140
|
-
} catch (error: any) {
|
|
141
|
-
console.error(
|
|
142
|
-
chalk.red("Error:"),
|
|
143
|
-
error instanceof Error ? error.message : "Unknown error"
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
} catch (error) {
|
|
147
|
-
console.error(
|
|
148
|
-
chalk.red("Error:"),
|
|
149
|
-
error instanceof Error ? error.message : "Unknown error"
|
|
150
246
|
);
|
|
247
|
+
} catch (error: any) {
|
|
248
|
+
if (error.message && error.message.includes('Authentication')) {
|
|
249
|
+
console.error(chalk.red(error.message));
|
|
250
|
+
} else if (error.response?.data?.message) {
|
|
251
|
+
console.error(chalk.red("API Error:"), error.response.data.message);
|
|
252
|
+
} else {
|
|
253
|
+
console.error(chalk.red("Error:"), error.message || "Unknown error");
|
|
254
|
+
}
|
|
151
255
|
}
|
|
152
256
|
});
|
|
153
257
|
|
|
@@ -162,109 +266,96 @@ export function registerAgentCommands(program: Command): void {
|
|
|
162
266
|
)
|
|
163
267
|
.action(async (options) => {
|
|
164
268
|
try {
|
|
165
|
-
|
|
166
|
-
console.error(
|
|
167
|
-
chalk.red("No authentication token found. Please login first.")
|
|
168
|
-
);
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
|
|
269
|
+
let apis = createApis();
|
|
172
270
|
const { agent } = options;
|
|
173
271
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
const agents = agentsResponse.data?.machineAgents || [];
|
|
193
|
-
|
|
194
|
-
// Find the specific agent by ID
|
|
195
|
-
const targetAgent = agents.find(
|
|
196
|
-
(a: any) => a.id.toString() === agent.toString()
|
|
197
|
-
);
|
|
198
|
-
|
|
199
|
-
if (!targetAgent) {
|
|
200
|
-
spinner.fail(
|
|
201
|
-
`Agent with ID ${agent} not found in project ${projectData.name}`
|
|
202
|
-
);
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
272
|
+
await withTokenRefresh(
|
|
273
|
+
async () => {
|
|
274
|
+
// Resolve project
|
|
275
|
+
const projectData = await resolveProject(apis.projectsApi, options);
|
|
276
|
+
|
|
277
|
+
const spinner = ora(
|
|
278
|
+
`Finding agent ${agent} in project ${projectData.name}...`
|
|
279
|
+
).start();
|
|
280
|
+
|
|
281
|
+
try {
|
|
282
|
+
// Get the list of agents to find the correct modelbaseId
|
|
283
|
+
const agentsResponse: any =
|
|
284
|
+
await apis.agentsApi.machineAgentControllerGetMachineAgentByProjectId(
|
|
285
|
+
projectData.id,
|
|
286
|
+
0,
|
|
287
|
+
100,
|
|
288
|
+
AgentType.REGULAR
|
|
289
|
+
);
|
|
205
290
|
|
|
206
|
-
|
|
207
|
-
|
|
291
|
+
const agents = agentsResponse.data?.machineAgents || [];
|
|
292
|
+
const targetAgent = agents.find(
|
|
293
|
+
(a: any) => a.id.toString() === agent.toString()
|
|
294
|
+
);
|
|
208
295
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
296
|
+
if (!targetAgent) {
|
|
297
|
+
spinner.fail(
|
|
298
|
+
`Agent with ID ${agent} not found in project ${projectData.name}`
|
|
299
|
+
);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
215
302
|
|
|
216
|
-
|
|
303
|
+
const modelbaseId = targetAgent.modelBaseId;
|
|
304
|
+
if (!modelbaseId) {
|
|
305
|
+
spinner.fail(
|
|
306
|
+
`Could not find modelbaseId for agent ${agent}. Please try again.`
|
|
307
|
+
);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
217
310
|
|
|
218
|
-
|
|
219
|
-
const payload: any = [
|
|
220
|
-
{
|
|
221
|
-
id: parseInt(agent, 10),
|
|
222
|
-
modelbaseId: modelbaseId,
|
|
223
|
-
},
|
|
224
|
-
];
|
|
311
|
+
spinner.text = `Removing agent ${agent} from project ${projectData.name}...`;
|
|
225
312
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
313
|
+
// Remove the agent
|
|
314
|
+
const payload: any = [
|
|
315
|
+
{
|
|
316
|
+
id: parseInt(agent, 10),
|
|
317
|
+
modelbaseId: modelbaseId,
|
|
318
|
+
},
|
|
319
|
+
];
|
|
232
320
|
|
|
233
|
-
|
|
321
|
+
await apis.agentsApi.machineAgentControllerDeleteMachineAgents(
|
|
322
|
+
projectData.id,
|
|
323
|
+
agent,
|
|
324
|
+
payload
|
|
325
|
+
);
|
|
234
326
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
);
|
|
248
|
-
} else {
|
|
249
|
-
console.error(
|
|
250
|
-
chalk.red("Error:"),
|
|
251
|
-
error.message || "Unknown error"
|
|
252
|
-
);
|
|
327
|
+
spinner.succeed("Successfully removed agent");
|
|
328
|
+
console.log(
|
|
329
|
+
chalk.green(
|
|
330
|
+
`Agent ${agent} removed successfully from project ${projectData.name}`
|
|
331
|
+
)
|
|
332
|
+
);
|
|
333
|
+
} catch (error: any) {
|
|
334
|
+
spinner.fail("Failed to remove agent");
|
|
335
|
+
throw error;
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
() => {
|
|
339
|
+
apis = createApis();
|
|
253
340
|
}
|
|
254
|
-
}
|
|
255
|
-
} catch (error) {
|
|
256
|
-
console.error(
|
|
257
|
-
chalk.red("Error:"),
|
|
258
|
-
error instanceof Error ? error.message : "Unknown error"
|
|
259
341
|
);
|
|
342
|
+
} catch (error: any) {
|
|
343
|
+
if (error.message && error.message.includes('Authentication')) {
|
|
344
|
+
console.error(chalk.red(error.message));
|
|
345
|
+
} else if (error.response?.data?.message) {
|
|
346
|
+
console.error(chalk.red("API Error:"), error.response.data.message);
|
|
347
|
+
} else {
|
|
348
|
+
console.error(chalk.red("Error:"), error.message || "Unknown error");
|
|
349
|
+
}
|
|
260
350
|
}
|
|
261
351
|
});
|
|
262
352
|
|
|
263
353
|
agentCommand
|
|
264
354
|
.command("deploy")
|
|
265
355
|
.description("Deploy an AI agent to the Nestbox platform")
|
|
266
|
-
.
|
|
267
|
-
.
|
|
356
|
+
.option("--agent <agentName>", "Agent name to deploy")
|
|
357
|
+
.option("--chatbot <chatbotName>", "Chatbot name to deploy")
|
|
358
|
+
.requiredOption("--instance <instanceName>", "Instance name")
|
|
268
359
|
.option(
|
|
269
360
|
"--zip <zipFileOrDirPath>",
|
|
270
361
|
"Path to the zip file or directory to upload"
|
|
@@ -276,147 +367,519 @@ export function registerAgentCommands(program: Command): void {
|
|
|
276
367
|
.option("--entry <entryFunction>", "Entry function name", "main")
|
|
277
368
|
.action(async (options) => {
|
|
278
369
|
try {
|
|
279
|
-
|
|
370
|
+
const {
|
|
371
|
+
agent: agentName,
|
|
372
|
+
chatbot: chatbotName,
|
|
373
|
+
instance: instanceName,
|
|
374
|
+
zip: customZipPath,
|
|
375
|
+
entry,
|
|
376
|
+
} = options;
|
|
377
|
+
|
|
378
|
+
// Ensure either agent or chatbot is provided, but not both
|
|
379
|
+
if ((!agentName && !chatbotName) || (agentName && chatbotName)) {
|
|
280
380
|
console.error(
|
|
281
|
-
chalk.red("
|
|
381
|
+
chalk.red("Please provide either --agent OR --chatbot option, but not both.")
|
|
282
382
|
);
|
|
283
383
|
return;
|
|
284
384
|
}
|
|
285
385
|
|
|
286
|
-
|
|
287
|
-
agent: agentId,
|
|
288
|
-
instance: instanceId,
|
|
289
|
-
zip: customZipPath,
|
|
290
|
-
entry,
|
|
291
|
-
} = options;
|
|
386
|
+
let apis = createApis();
|
|
292
387
|
|
|
293
|
-
// Find project root
|
|
388
|
+
// Find project root
|
|
294
389
|
const projectRoot = await findProjectRoot();
|
|
295
390
|
console.log(chalk.blue(`Project root detected at: ${projectRoot}`));
|
|
296
391
|
|
|
297
|
-
//
|
|
298
|
-
|
|
392
|
+
// Main deployment logic with token refresh
|
|
393
|
+
await withTokenRefresh(
|
|
394
|
+
async () => {
|
|
395
|
+
// Resolve project
|
|
396
|
+
const projectData = await resolveProject(apis.projectsApi, options);
|
|
397
|
+
|
|
398
|
+
// Determine if we're deploying an agent or chatbot
|
|
399
|
+
const isAgent = !!agentName;
|
|
400
|
+
const resourceName = isAgent ? agentName : chatbotName;
|
|
401
|
+
const resourceType = isAgent ? "Agent" : "Chatbot";
|
|
402
|
+
const agentType = isAgent ? AgentType.REGULAR : "CHAT";
|
|
403
|
+
|
|
404
|
+
// Get agents data and find agent/chatbot by name
|
|
405
|
+
const agentsData: any = await apis.agentsApi.machineAgentControllerGetMachineAgentByProjectId(
|
|
406
|
+
projectData.id,
|
|
407
|
+
0,
|
|
408
|
+
10,
|
|
409
|
+
agentType
|
|
410
|
+
);
|
|
299
411
|
|
|
300
|
-
|
|
301
|
-
|
|
412
|
+
const targetAgent = agentsData.data.machineAgents.find(
|
|
413
|
+
(agent: any) => agent.agentName === resourceName
|
|
414
|
+
);
|
|
302
415
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
416
|
+
if (!targetAgent) {
|
|
417
|
+
console.error(
|
|
418
|
+
chalk.red(`${resourceType} with name "${resourceName}" not found in project "${projectData.name}".`)
|
|
419
|
+
);
|
|
420
|
+
console.log(chalk.yellow(`Available ${resourceType.toLowerCase()}s:`));
|
|
421
|
+
agentsData.data.machineAgents.forEach((agent: any) => {
|
|
422
|
+
console.log(chalk.yellow(` - ${agent.agentName} (ID: ${agent.id})`));
|
|
423
|
+
});
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
307
426
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
427
|
+
// Get instance data and find instance by name
|
|
428
|
+
const instanceData: any = await apis.instanceApi.machineInstancesControllerGetMachineInstanceByUserId(
|
|
429
|
+
projectData.id,
|
|
430
|
+
0,
|
|
431
|
+
10
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
const targetInstance = instanceData.data.machineInstances.find(
|
|
435
|
+
(instance: any) => instance.instanceName === instanceName
|
|
436
|
+
);
|
|
311
437
|
|
|
312
|
-
|
|
438
|
+
if (!targetInstance) {
|
|
439
|
+
console.error(
|
|
440
|
+
chalk.red(`Instance with name "${instanceName}" not found in project "${projectData.name}".`)
|
|
441
|
+
);
|
|
442
|
+
console.log(chalk.yellow("Available instances:"));
|
|
443
|
+
instanceData.data.machineInstances.forEach((instance: any) => {
|
|
444
|
+
console.log(chalk.yellow(` - ${instance.instanceName} (ID: ${instance.id})`));
|
|
445
|
+
});
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
313
448
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
449
|
+
// Extract IDs
|
|
450
|
+
const agentId = targetAgent.id;
|
|
451
|
+
const instanceId = targetInstance.id;
|
|
452
|
+
|
|
453
|
+
// Load nestbox.config.json
|
|
454
|
+
const config = loadNestboxConfig(projectRoot);
|
|
455
|
+
|
|
456
|
+
// Start the deployment process
|
|
457
|
+
const spinner = ora(
|
|
458
|
+
`Preparing to deploy ${resourceType.toLowerCase()} ${agentId} to instance ${instanceId}...`
|
|
459
|
+
).start();
|
|
460
|
+
|
|
461
|
+
try {
|
|
462
|
+
let zipFilePath;
|
|
463
|
+
|
|
464
|
+
if (customZipPath) {
|
|
465
|
+
// Process custom zip path
|
|
466
|
+
if (!fs.existsSync(customZipPath)) {
|
|
467
|
+
spinner.fail(`Path not found: ${customZipPath}`);
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const stats = fs.statSync(customZipPath);
|
|
472
|
+
|
|
473
|
+
if (stats.isFile()) {
|
|
474
|
+
if (!customZipPath.toLowerCase().endsWith(".zip")) {
|
|
475
|
+
spinner.fail(`File is not a zip archive: ${customZipPath}`);
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
spinner.text = `Using provided zip file: ${customZipPath}`;
|
|
479
|
+
zipFilePath = customZipPath;
|
|
480
|
+
} else if (stats.isDirectory()) {
|
|
481
|
+
// Process directory
|
|
482
|
+
spinner.text = `Processing directory: ${customZipPath}`;
|
|
483
|
+
|
|
484
|
+
const isTypeScript = isTypeScriptProject(customZipPath);
|
|
485
|
+
|
|
486
|
+
if (isTypeScript && (config?.agent?.predeploy || config?.agents?.predeploy)) {
|
|
487
|
+
const predeployScripts = config?.agent?.predeploy || config?.agents?.predeploy;
|
|
488
|
+
spinner.text = `Running predeploy scripts on target directory...`;
|
|
489
|
+
await runPredeployScripts(predeployScripts, customZipPath);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
spinner.text = `Creating zip archive from directory ${customZipPath}...`;
|
|
493
|
+
zipFilePath = createZipFromDirectory(customZipPath);
|
|
494
|
+
spinner.text = `Directory zipped successfully to ${zipFilePath}`;
|
|
495
|
+
}
|
|
496
|
+
} else {
|
|
497
|
+
// Use project root
|
|
498
|
+
spinner.text = `Using project root: ${projectRoot}`;
|
|
499
|
+
|
|
500
|
+
const isTypeScript = isTypeScriptProject(projectRoot);
|
|
501
|
+
|
|
502
|
+
if (isTypeScript && (config?.agent?.predeploy || config?.agents?.predeploy)) {
|
|
503
|
+
const predeployScripts = config?.agent?.predeploy || config?.agents?.predeploy;
|
|
504
|
+
spinner.text = `Running predeploy scripts on project root...`;
|
|
505
|
+
await runPredeployScripts(predeployScripts, projectRoot);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
spinner.text = `Creating zip archive from project root ${projectRoot}...`;
|
|
509
|
+
zipFilePath = createZipFromDirectory(projectRoot);
|
|
510
|
+
spinner.text = `Directory zipped successfully to ${zipFilePath}`;
|
|
511
|
+
}
|
|
319
512
|
|
|
320
|
-
|
|
321
|
-
|
|
513
|
+
spinner.text = `Deploying ${resourceType.toLowerCase()} ${agentId} to instance ${instanceId}...`;
|
|
514
|
+
|
|
515
|
+
// Prepare deployment
|
|
516
|
+
const authToken = getAuthToken();
|
|
517
|
+
const baseUrl = authToken?.serverUrl?.endsWith("/")
|
|
518
|
+
? authToken.serverUrl.slice(0, -1)
|
|
519
|
+
: authToken?.serverUrl;
|
|
520
|
+
|
|
521
|
+
const { default: FormData } = await import("form-data");
|
|
522
|
+
const form = new FormData();
|
|
523
|
+
|
|
524
|
+
form.append("file", fs.createReadStream(zipFilePath));
|
|
525
|
+
form.append("machineAgentId", agentId.toString());
|
|
526
|
+
form.append("instanceId", instanceId.toString());
|
|
527
|
+
form.append("entryFunctionName", entry);
|
|
528
|
+
form.append("isSourceCodeUpdate", "true");
|
|
529
|
+
form.append("projectId", projectData.id);
|
|
530
|
+
|
|
531
|
+
const axiosInstance = axios.create({
|
|
532
|
+
baseURL: baseUrl,
|
|
533
|
+
headers: {
|
|
534
|
+
...form.getHeaders(),
|
|
535
|
+
Authorization: authToken?.token,
|
|
536
|
+
},
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
const endpoint = `/projects/${projectData.id}/agents/${agentId}`;
|
|
540
|
+
|
|
541
|
+
console.log(chalk.blue("\nMaking API request:"));
|
|
542
|
+
console.log(chalk.blue(` URL: ${baseUrl}${endpoint}`));
|
|
543
|
+
console.log(chalk.blue(` Method: PATCH`));
|
|
544
|
+
console.log(chalk.blue(` File: ${path.basename(zipFilePath)}`));
|
|
545
|
+
|
|
546
|
+
spinner.text = `Sending API request to deploy ${resourceType.toLowerCase()}...`;
|
|
547
|
+
const res = await axiosInstance.patch(endpoint, form);
|
|
548
|
+
|
|
549
|
+
console.log(chalk.green("\nAPI Response received:"));
|
|
550
|
+
console.log(chalk.green(` Status: ${res.status} ${res.statusText}`));
|
|
551
|
+
|
|
552
|
+
if (!customZipPath && zipFilePath && fs.existsSync(zipFilePath)) {
|
|
553
|
+
fs.unlinkSync(zipFilePath);
|
|
554
|
+
}
|
|
322
555
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
556
|
+
spinner.succeed(
|
|
557
|
+
`Successfully deployed ${resourceType.toLowerCase()} ${agentId} to instance ${instanceId}`
|
|
558
|
+
);
|
|
559
|
+
console.log(chalk.green(`${resourceType} deployed successfully`));
|
|
560
|
+
} catch (error: any) {
|
|
561
|
+
spinner.fail(`Failed to deploy ${resourceType.toLowerCase()}`);
|
|
562
|
+
throw error;
|
|
328
563
|
}
|
|
564
|
+
},
|
|
565
|
+
() => {
|
|
566
|
+
apis = createApis();
|
|
567
|
+
}
|
|
568
|
+
);
|
|
569
|
+
} catch (error: any) {
|
|
570
|
+
if (error.message && error.message.includes('Authentication')) {
|
|
571
|
+
console.error(chalk.red(error.message));
|
|
572
|
+
} else if (error.response) {
|
|
573
|
+
console.error(
|
|
574
|
+
chalk.red(
|
|
575
|
+
`API Error (${error.response.status}): ${error.response.data?.message || "Unknown error"}`
|
|
576
|
+
)
|
|
577
|
+
);
|
|
578
|
+
if (error.response.data) {
|
|
579
|
+
console.error(chalk.red(`Error Data: ${JSON.stringify(error.response.data, null, 2)}`));
|
|
580
|
+
}
|
|
581
|
+
} else {
|
|
582
|
+
console.error(chalk.red("Error:"), error.message || "Unknown error");
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
});
|
|
329
586
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
587
|
+
agentCommand
|
|
588
|
+
.command("generate <folder>")
|
|
589
|
+
.description("Generate a new project from templates")
|
|
590
|
+
.option("--lang <language>", "Project language (ts|js)")
|
|
591
|
+
.option("--template <type>", "Template type (agent|chatbot)")
|
|
592
|
+
.option("--project <projectId>", "Project ID")
|
|
593
|
+
.action(async (folder, options) => {
|
|
594
|
+
try {
|
|
595
|
+
const spinner = ora("Initializing project generation...").start();
|
|
335
596
|
|
|
336
|
-
|
|
337
|
-
|
|
597
|
+
// Ensure target folder doesn't exist
|
|
598
|
+
if (fs.existsSync(folder)) {
|
|
599
|
+
spinner.fail(`Folder ${folder} already exists`);
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
338
602
|
|
|
339
|
-
|
|
340
|
-
|
|
603
|
+
let selectedLang = options.lang;
|
|
604
|
+
let selectedTemplate = options.template;
|
|
341
605
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
606
|
+
// Interactive selection if not provided
|
|
607
|
+
if (!selectedLang || !selectedTemplate) {
|
|
608
|
+
spinner.stop();
|
|
609
|
+
|
|
610
|
+
const answers = await inquirer.prompt([
|
|
611
|
+
{
|
|
612
|
+
type: 'list',
|
|
613
|
+
name: 'lang',
|
|
614
|
+
message: 'Select project language:',
|
|
615
|
+
choices: [
|
|
616
|
+
{ name: 'TypeScript', value: 'ts' },
|
|
617
|
+
{ name: 'JavaScript', value: 'js' }
|
|
618
|
+
],
|
|
619
|
+
when: () => !selectedLang
|
|
620
|
+
},
|
|
621
|
+
{
|
|
622
|
+
type: 'list',
|
|
623
|
+
name: 'template',
|
|
624
|
+
message: 'Select template type:',
|
|
625
|
+
choices: [
|
|
626
|
+
{ name: 'Agent', value: 'agent' },
|
|
627
|
+
{ name: 'Chatbot', value: 'chatbot' }
|
|
628
|
+
],
|
|
629
|
+
when: () => !selectedTemplate
|
|
356
630
|
}
|
|
631
|
+
]);
|
|
357
632
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
spinner.fail(`Unsupported file type: ${sourcePath}`);
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
spinner.text = `Deploying agent ${agentId} to instance ${instanceId}...`;
|
|
633
|
+
selectedLang = selectedLang || answers.lang;
|
|
634
|
+
selectedTemplate = selectedTemplate || answers.template;
|
|
635
|
+
|
|
636
|
+
spinner.start("Generating project...");
|
|
637
|
+
}
|
|
368
638
|
|
|
369
|
-
// Clean the base URL to avoid path duplication
|
|
370
|
-
const baseUrl = authToken?.serverUrl?.endsWith("/")
|
|
371
|
-
? authToken.serverUrl.slice(0, -1)
|
|
372
|
-
: authToken?.serverUrl;
|
|
373
639
|
|
|
374
|
-
|
|
375
|
-
|
|
640
|
+
// Find matching template in local templates folder
|
|
641
|
+
const templateMapping: Record<string, string> = {
|
|
642
|
+
'agent': 'base',
|
|
643
|
+
'chatbot': 'chatbot'
|
|
644
|
+
};
|
|
645
|
+
const mappedTemplateType = templateMapping[selectedTemplate] || selectedTemplate;
|
|
646
|
+
const templateKey = `template-${mappedTemplateType}-${selectedLang}.zip`;
|
|
647
|
+
// Try process.cwd() first, then __dirname fallback
|
|
648
|
+
let templatePath = path.resolve(process.cwd(), 'templates', templateKey);
|
|
649
|
+
if (!fs.existsSync(templatePath)) {
|
|
650
|
+
// fallback to __dirname
|
|
651
|
+
templatePath = path.resolve(__dirname, '../../templates', templateKey);
|
|
652
|
+
}
|
|
653
|
+
if (!fs.existsSync(templatePath)) {
|
|
654
|
+
spinner.fail(`Template not found: ${templatePath}`);
|
|
655
|
+
// Show available templates in both locations
|
|
656
|
+
const cwdTemplates = path.resolve(process.cwd(), 'templates');
|
|
657
|
+
const dirTemplates = path.resolve(__dirname, '../../templates');
|
|
658
|
+
let shown = false;
|
|
659
|
+
if (fs.existsSync(cwdTemplates)) {
|
|
660
|
+
console.log(chalk.yellow('Available templates in ./templates:'));
|
|
661
|
+
fs.readdirSync(cwdTemplates).forEach(file => {
|
|
662
|
+
console.log(chalk.yellow(` - ${file}`));
|
|
663
|
+
});
|
|
664
|
+
shown = true;
|
|
665
|
+
}
|
|
666
|
+
if (fs.existsSync(dirTemplates)) {
|
|
667
|
+
console.log(chalk.yellow('Available templates in src/commands/../../templates:'));
|
|
668
|
+
fs.readdirSync(dirTemplates).forEach(file => {
|
|
669
|
+
console.log(chalk.yellow(` - ${file}`));
|
|
670
|
+
});
|
|
671
|
+
shown = true;
|
|
672
|
+
}
|
|
673
|
+
if (!shown) {
|
|
674
|
+
console.log(chalk.red('No templates directory found. Please add your templates.'));
|
|
675
|
+
}
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
376
678
|
|
|
377
|
-
|
|
378
|
-
form.append("file", fs.createReadStream(zipFilePath));
|
|
679
|
+
spinner.text = `Extracting template to ${folder}...`;
|
|
379
680
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
681
|
+
try {
|
|
682
|
+
// Extract template to target folder
|
|
683
|
+
extractZip(templatePath, folder);
|
|
684
|
+
|
|
685
|
+
// Create nestbox.config.json for TypeScript projects
|
|
686
|
+
createNestboxConfig(folder, selectedLang === 'ts');
|
|
687
|
+
|
|
688
|
+
// Update package.json with project name if it exists
|
|
689
|
+
const packageJsonPath = path.join(folder, 'package.json');
|
|
690
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
691
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
692
|
+
packageJson.name = path.basename(folder);
|
|
693
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
694
|
+
}
|
|
386
695
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
}
|
|
696
|
+
spinner.succeed(`Successfully generated ${mappedTemplateType} project in ${folder}`);
|
|
697
|
+
|
|
698
|
+
console.log(chalk.green("\nNext steps:"));
|
|
699
|
+
console.log(chalk.yellow(` cd ${folder}`));
|
|
700
|
+
console.log(chalk.yellow(" npm install"));
|
|
701
|
+
if (selectedLang === 'ts') {
|
|
702
|
+
console.log(chalk.yellow(" npm run build"));
|
|
703
|
+
}
|
|
704
|
+
console.log(chalk.yellow(" nestbox agent deploy --agent <agent-name> --instance <instance-name>"));
|
|
395
705
|
|
|
396
|
-
|
|
397
|
-
|
|
706
|
+
} catch (error) {
|
|
707
|
+
// Clean up on error
|
|
708
|
+
if (fs.existsSync(folder)) {
|
|
709
|
+
fs.rmSync(folder, { recursive: true, force: true });
|
|
710
|
+
}
|
|
711
|
+
throw error;
|
|
712
|
+
}
|
|
398
713
|
|
|
399
|
-
|
|
400
|
-
|
|
714
|
+
} catch (error: any) {
|
|
715
|
+
console.error(
|
|
716
|
+
chalk.red("Error:"),
|
|
717
|
+
error.message || "Failed to generate project"
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
});
|
|
401
721
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
722
|
+
// Command for creating agents from YAML files
|
|
723
|
+
agentCommand
|
|
724
|
+
.command("create [firstArg] [secondArg]")
|
|
725
|
+
.description("Create multiple agents from a YAML configuration file")
|
|
726
|
+
.option("--project <projectId>", "Project ID (defaults to the current project)")
|
|
727
|
+
.action(async (firstArg: string, secondArg: any, options: any) => {
|
|
728
|
+
try {
|
|
729
|
+
let apis = createApis();
|
|
730
|
+
|
|
731
|
+
// Determine which argument is the YAML file path
|
|
732
|
+
let yamlFilePath: string;
|
|
733
|
+
|
|
734
|
+
if (firstArg === 'file' && secondArg) {
|
|
735
|
+
yamlFilePath = secondArg;
|
|
736
|
+
} else if (firstArg) {
|
|
737
|
+
yamlFilePath = firstArg;
|
|
738
|
+
if (typeof secondArg === 'object' && !options) {
|
|
739
|
+
options = secondArg;
|
|
405
740
|
}
|
|
741
|
+
} else {
|
|
742
|
+
console.error(chalk.red("Missing YAML file path. Usage: nestbox agent create <yamlFile> OR nestbox agent create file <yamlFile>"));
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
406
745
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
);
|
|
410
|
-
|
|
411
|
-
}
|
|
412
|
-
spinner.fail("Failed to deploy agent");
|
|
746
|
+
// Check if file exists
|
|
747
|
+
if (!fs.existsSync(yamlFilePath)) {
|
|
748
|
+
console.error(chalk.red(`YAML file not found: ${yamlFilePath}`));
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
413
751
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
752
|
+
// Read and parse the YAML file
|
|
753
|
+
const spinner = ora(`Reading agents configuration from ${yamlFilePath}...`).start();
|
|
754
|
+
|
|
755
|
+
try {
|
|
756
|
+
const fileContents = fs.readFileSync(yamlFilePath, 'utf8');
|
|
757
|
+
const config = yaml.load(fileContents) as AgentYamlConfig;
|
|
758
|
+
|
|
759
|
+
if (!config || !config.agents || !Array.isArray(config.agents)) {
|
|
760
|
+
spinner.fail("Invalid YAML configuration: Missing 'agents' array");
|
|
761
|
+
console.error(chalk.red("The YAML file should contain an 'agents' array with agent configurations"));
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
spinner.succeed(`Found ${config.agents.length} agents in configuration file`);
|
|
766
|
+
|
|
767
|
+
// Process each agent with token refresh support
|
|
768
|
+
const results = {
|
|
769
|
+
success: 0,
|
|
770
|
+
failed: 0,
|
|
771
|
+
agents: [] as Array<{name: string; success: boolean; message: string}>
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
// Get user data once
|
|
775
|
+
const user = await userData();
|
|
776
|
+
|
|
777
|
+
for (const agent of config.agents) {
|
|
778
|
+
if (!agent.name) {
|
|
779
|
+
console.log(chalk.yellow("Skipping agent with no name defined"));
|
|
780
|
+
results.failed++;
|
|
781
|
+
results.agents.push({
|
|
782
|
+
name: "unnamed",
|
|
783
|
+
success: false,
|
|
784
|
+
message: "Name is required"
|
|
785
|
+
});
|
|
786
|
+
continue;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
let agentType = agent.type || "CHAT";
|
|
790
|
+
const resourceType = agentType === "AGENT" ? "Agent" : "Chatbot";
|
|
791
|
+
|
|
792
|
+
const agentSpinner = ora(`Creating ${resourceType.toLowerCase()} '${agent.name}'...`).start();
|
|
793
|
+
|
|
794
|
+
try {
|
|
795
|
+
// Create agent with token refresh support
|
|
796
|
+
await withTokenRefresh(
|
|
797
|
+
async () => {
|
|
798
|
+
// Map YAML config to createAgent options
|
|
799
|
+
const createOptions = {
|
|
800
|
+
...options,
|
|
801
|
+
goal: agent.goal || "No goal specified",
|
|
802
|
+
modelBaseId: agent.modelBaseId || "",
|
|
803
|
+
instanceIP: agent.instanceIP || "localhost",
|
|
804
|
+
machineInstanceId: agent.machineInstanceId || 1,
|
|
805
|
+
machineManifestId: agent.machineManifestId || "default",
|
|
806
|
+
machineName: agent.machineName || `agent-${agent.name.toLowerCase()}`,
|
|
807
|
+
type: agentType,
|
|
808
|
+
userId: user.id,
|
|
809
|
+
parameters: agent.parameters ? agent.parameters.map((p: any) => {
|
|
810
|
+
return {
|
|
811
|
+
name: p.name || "unnamed",
|
|
812
|
+
description: p.description || "",
|
|
813
|
+
default: p.default || "",
|
|
814
|
+
isUserParam: p.isUserParam !== undefined ? p.isUserParam : true
|
|
815
|
+
};
|
|
816
|
+
}) : []
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
await createAgent(agent.name, createOptions, apis.agentsApi, apis.projectsApi);
|
|
820
|
+
},
|
|
821
|
+
() => {
|
|
822
|
+
apis = createApis();
|
|
823
|
+
}
|
|
824
|
+
);
|
|
825
|
+
|
|
826
|
+
agentSpinner.stop();
|
|
827
|
+
|
|
828
|
+
results.success++;
|
|
829
|
+
results.agents.push({
|
|
830
|
+
name: agent.name,
|
|
831
|
+
success: true,
|
|
832
|
+
message: `Created successfully`
|
|
833
|
+
});
|
|
834
|
+
} catch (error: any) {
|
|
835
|
+
agentSpinner.fail(`Failed to create ${resourceType.toLowerCase()} '${agent.name}'`);
|
|
836
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
|
837
|
+
results.failed++;
|
|
838
|
+
results.agents.push({
|
|
839
|
+
name: agent.name,
|
|
840
|
+
success: false,
|
|
841
|
+
message: error.message
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// Final summary
|
|
847
|
+
console.log(chalk.blue("\nResource creation summary:"));
|
|
848
|
+
const table = new Table({
|
|
849
|
+
head: [
|
|
850
|
+
chalk.white.bold("Name"),
|
|
851
|
+
chalk.white.bold("Type"),
|
|
852
|
+
chalk.white.bold("Status"),
|
|
853
|
+
chalk.white.bold("Message"),
|
|
854
|
+
],
|
|
855
|
+
style: {
|
|
856
|
+
head: [],
|
|
857
|
+
border: [],
|
|
858
|
+
},
|
|
859
|
+
});
|
|
860
|
+
|
|
861
|
+
results.agents.forEach((agent, index) => {
|
|
862
|
+
const agentConfig = config.agents.find(a => a.name === agent.name) || config.agents[index];
|
|
863
|
+
const agentType = agentConfig?.type || "CHAT";
|
|
864
|
+
const resourceType = agentType === "AGENT" ? "Agent" : "Chatbot";
|
|
865
|
+
|
|
866
|
+
table.push([
|
|
867
|
+
agent.name,
|
|
868
|
+
resourceType,
|
|
869
|
+
agent.success ? chalk.green("Success") : chalk.red("Failed"),
|
|
870
|
+
agent.message
|
|
871
|
+
]);
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
console.log(table.toString());
|
|
875
|
+
console.log(`\nTotal: ${results.success + results.failed}, Successful: ${results.success}, Failed: ${results.failed}`);
|
|
876
|
+
|
|
877
|
+
} catch (error: any) {
|
|
878
|
+
spinner.fail("Failed to process YAML file");
|
|
879
|
+
if (error.code === 'ENOENT') {
|
|
880
|
+
console.error(chalk.red(`File not found: ${yamlFilePath}`));
|
|
881
|
+
} else if (error.name === 'YAMLException') {
|
|
882
|
+
console.error(chalk.red(`Invalid YAML format: ${error.message}`));
|
|
420
883
|
} else {
|
|
421
884
|
console.error(
|
|
422
885
|
chalk.red("Error:"),
|
|
@@ -424,11 +887,15 @@ export function registerAgentCommands(program: Command): void {
|
|
|
424
887
|
);
|
|
425
888
|
}
|
|
426
889
|
}
|
|
427
|
-
} catch (error) {
|
|
428
|
-
|
|
429
|
-
chalk.red(
|
|
430
|
-
|
|
431
|
-
|
|
890
|
+
} catch (error: any) {
|
|
891
|
+
if (error.message && error.message.includes('Authentication')) {
|
|
892
|
+
console.error(chalk.red(error.message));
|
|
893
|
+
} else {
|
|
894
|
+
console.error(
|
|
895
|
+
chalk.red("Error:"),
|
|
896
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
897
|
+
);
|
|
898
|
+
}
|
|
432
899
|
}
|
|
433
900
|
});
|
|
434
|
-
}
|
|
901
|
+
}
|