@nestbox-ai/cli
Version:
The cli tools that helps developers to build agents
319 lines • 18.9 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.selectTargetAgent = selectTargetAgent;
exports.registerDeployCommand = registerDeployCommand;
const chalk_1 = __importDefault(require("chalk"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const auth_1 = require("../../utils/auth");
const error_1 = require("../../utils/error");
const ora_1 = __importDefault(require("ora"));
const project_1 = require("../../utils/project");
const agent_1 = require("../../utils/agent");
const axios_1 = __importDefault(require("axios"));
const apiUtils_1 = require("./apiUtils");
const inquirer_1 = __importDefault(require("inquirer"));
function selectTargetAgent(agents, agentName, instance) {
const matchingByName = agents.filter(agent => agent.agentName === agentName);
if (!matchingByName.length) {
return undefined;
}
if (instance.id !== undefined) {
const byInstanceId = matchingByName.find(agent => agent.machineInstanceId === instance.id);
if (byInstanceId && byInstanceId.id !== undefined) {
return byInstanceId;
}
}
if (instance.instanceName) {
const byInstanceName = matchingByName.find(agent => agent.machineName === instance.instanceName);
if (byInstanceName && byInstanceName.id !== undefined) {
return byInstanceName;
}
}
if (instance.id !== undefined || instance.instanceName) {
return undefined;
}
if (matchingByName.length === 1 && matchingByName[0].id !== undefined) {
return matchingByName[0];
}
return undefined;
}
function buildAgentData(options_1) {
return __awaiter(this, arguments, void 0, function* (options, machineInstanceData = {}) {
const deployAgentData = {
agentName: "",
goal: "",
inputSchema: {},
machineManifestId: machineInstanceData.machineId,
machineName: options.instance,
machineInstanceId: machineInstanceData.id,
instanceIP: machineInstanceData.internalIP,
projectId: options.project,
type: (options === null || options === void 0 ? void 0 : options.type) || "REGULAR",
userId: 0,
modelBaseId: "",
entryFunctionName: "",
};
if (!options.agent) {
throw new Error("Missing required argument <agent>.");
}
deployAgentData.agentName = options.prefix
? options.prefix + "-" + options.agent
: options.agent;
if (options.description || options.inputSchema || options.entryFunction) {
if (!options.description) {
throw new Error("Missing required argument <description>.");
}
if (!options.inputSchema) {
throw new Error("Missing required argument <inputSchema>.");
}
if (!options.entryFunction) {
throw new Error("Missing required argument <entryFunction>.");
}
deployAgentData.goal = options.description;
deployAgentData.inputSchema = JSON.parse(options.inputSchema);
deployAgentData.entryFunctionName = options.entryFunction;
}
else {
const manifestAgent = yield (0, apiUtils_1.loadAgentFromYaml)(options.agent);
if (!manifestAgent) {
throw new Error("Could not find a yaml file definition of an agent or agent not defined in yaml file.");
}
deployAgentData.entryFunctionName = manifestAgent.entry;
deployAgentData.goal = manifestAgent.description;
deployAgentData.inputSchema = manifestAgent.inputSchema || {};
deployAgentData.type = options.type || (manifestAgent === null || manifestAgent === void 0 ? void 0 : manifestAgent.type) || "REGULAR";
}
return deployAgentData;
});
}
function registerDeployCommand(agentCommand) {
agentCommand
.command("deploy")
.description("Deploy an AI agent to the Nestbox platform")
.option("--prefix <prefix>", "A prefix added to beginning of the agent name.")
.option("--agent <agent>", "Agent name to deploy")
.option("--description <description>", "Goal/description of the agent")
.option("--inputSchema <inputSchema>", "Agent input schema")
.option("--project <project>", "Project ID (defaults to current project)")
.option("--type <type>", "Agent type (e.g. CHAT, AGENT, REGULAR)")
.option("--entryFunction <entryFunction>", "Entry function name")
.option("--instance <instance>", "Machine name")
.option("--log", "Show detailed logs during deployment")
.option("--silent", "Disable automatic agent creation.")
.option("--all", "Deploy all agents defined in nestbox-agents.yaml")
.action((options) => __awaiter(this, void 0, void 0, function* () {
var _a;
try {
let apis = (0, apiUtils_1.createApis)();
yield (0, error_1.withTokenRefresh)(() => __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e;
let names = [];
if (options.all) {
names = yield (0, apiUtils_1.loadAllAgentNamesFromYaml)();
if (!names.length) {
console.log(chalk_1.default.yellow("No agents found in YAML manifest."));
return;
}
}
else {
if (!(options === null || options === void 0 ? void 0 : options.agent)) {
console.log(chalk_1.default.red("Parameter <agent> not provided."));
return;
}
names = [options.agent];
}
const projectData = yield (0, project_1.resolveProject)(apis.projectsApi, Object.assign({ project: options.project, instance: "" }, options));
const projectRoot = process.cwd();
const config = (0, agent_1.loadNestboxConfig)(projectRoot);
if (!(options === null || options === void 0 ? void 0 : options.instance) && !(config === null || config === void 0 ? void 0 : config.instance)) {
console.log(chalk_1.default.red("Parameter <instance> not provided."));
return;
}
const machineName = options.instance || config.instance;
const instanceData = yield apis.instanceApi.machineInstancesControllerGetMachineInstanceByUserId(projectData.id, 0, 10);
const targetInstance = instanceData.data.machineInstances.find((instance) => instance.instanceName === machineName);
if (!targetInstance) {
console.error(chalk_1.default.red(`Instance with name "${machineName}" not found in project "${projectData.name}".`));
console.log(chalk_1.default.yellow("Available instances:"));
instanceData.data.machineInstances.forEach((instance) => {
console.log(chalk_1.default.yellow(` - ${instance.instanceName} (ID: ${instance.id})`));
});
return;
}
for (const name of names) {
const data = yield buildAgentData(Object.assign(Object.assign({}, options), { project: projectData.id, instance: machineName, agent: name }), targetInstance);
const agentsData = yield apis.agentsApi.machineAgentControllerGetMachineAgentByProjectId(projectData.id, 0, 100, data.type);
let targetAgent = selectTargetAgent(agentsData.data.machineAgents, data.agentName, {
id: targetInstance.id,
instanceName: targetInstance.instanceName,
});
if (!targetAgent && !options.silent) {
const { confirmCreation } = yield inquirer_1.default.prompt([
{
type: "confirm",
name: "confirmCreation",
message: chalk_1.default.red(`No agent with specified name "${data.agentName}" found. Would you like to create one first before deployment?`),
default: false,
},
]);
if (!confirmCreation) {
continue;
}
}
if (!targetAgent) {
const response = yield apis.agentsApi.machineAgentControllerCreateMachineAgent(projectData.id, Object.assign({}, data));
targetAgent = response.data;
console.log(chalk_1.default.green(`Created agent ${data.agentName} before deploying.`));
}
const agentId = targetAgent === null || targetAgent === void 0 ? void 0 : targetAgent.id;
if (agentId === undefined) {
throw new Error(`Unable to resolve an agent ID for ${data.agentName} on instance ${machineName}.`);
}
const resolvedEntry = data.entryFunctionName ||
(targetAgent === null || targetAgent === void 0 ? void 0 : targetAgent.entryFunctionName) ||
"main";
const instanceId = targetInstance.id;
const spinner = (0, ora_1.default)(`Preparing to deploy ${data.agentName.toLowerCase()} ${agentId} to instance ${instanceId}...`).start();
try {
let zipFilePath;
spinner.text = `Using project root: ${projectRoot}`;
const isTypeScript = (0, agent_1.isTypeScriptProject)(projectRoot);
if (isTypeScript &&
(((_a = config === null || config === void 0 ? void 0 : config.agent) === null || _a === void 0 ? void 0 : _a.predeploy) ||
((_b = config === null || config === void 0 ? void 0 : config.agents) === null || _b === void 0 ? void 0 : _b.predeploy))) {
const predeployScripts = ((_c = config === null || config === void 0 ? void 0 : config.agent) === null || _c === void 0 ? void 0 : _c.predeploy) ||
((_d = config === null || config === void 0 ? void 0 : config.agents) === null || _d === void 0 ? void 0 : _d.predeploy);
spinner.text = `Running predeploy scripts on project root...`;
yield (0, agent_1.runPredeployScripts)(predeployScripts, projectRoot);
}
spinner.text = `Creating zip archive from project root ${projectRoot}...`;
const excludePatterns = (0, agent_1.getAgentExcludePatterns)(config);
zipFilePath = (0, agent_1.createZipFromDirectory)(projectRoot, excludePatterns);
const authToken = (0, auth_1.getAuthToken)();
const baseUrl = ((_e = authToken === null || authToken === void 0 ? void 0 : authToken.serverUrl) === null || _e === void 0 ? void 0 : _e.endsWith("/"))
? authToken.serverUrl.slice(0, -1)
: authToken === null || authToken === void 0 ? void 0 : authToken.serverUrl;
const { default: FormData } = yield Promise.resolve().then(() => __importStar(require("form-data")));
const form = new FormData();
form.append("file", fs_1.default.createReadStream(zipFilePath));
form.append("machineAgentId", agentId.toString());
form.append("instanceId", instanceId.toString());
form.append("entryFunctionName", resolvedEntry);
form.append("isSourceCodeUpdate", "true");
form.append("projectId", projectData.id);
if (options.log) {
console.log(chalk_1.default.blue("Form Details "));
console.log(chalk_1.default.blue(` - File: ${path_1.default.basename(zipFilePath)}`));
console.log(chalk_1.default.blue(` - Agent ID: ${agentId}`));
console.log(chalk_1.default.blue(` - Instance ID: ${instanceId}`));
console.log(chalk_1.default.blue(` - Entry Function: ${resolvedEntry}`));
console.log(chalk_1.default.blue(` - Project ID: ${projectData.id}`));
}
const axiosInstance = axios_1.default.create({
baseURL: baseUrl,
headers: Object.assign(Object.assign({}, form.getHeaders()), { Authorization: authToken === null || authToken === void 0 ? void 0 : authToken.token }),
});
const endpoint = `/projects/${projectData.id}/agents/${agentId}`;
spinner.text = `Deploying ${data.agentName.toLowerCase()} ${agentId} to instance ${instanceId} with file ${zipFilePath}...`;
const res = yield axiosInstance.patch(endpoint, form);
yield axios_1.default.patch(baseUrl + endpoint, {
projectId: data.projectId,
id: agentId,
agentName: data.agentName,
goal: data.goal,
inputSchema: data.inputSchema,
}, {
headers: {
Authorization: authToken === null || authToken === void 0 ? void 0 : authToken.token,
},
});
if (options.log) {
console.log(chalk_1.default.blue("\nDeployment request:"));
console.log(chalk_1.default.blue(` URL: ${baseUrl}${endpoint}`));
console.log(chalk_1.default.blue(` Method: PATCH`));
console.log(chalk_1.default.blue(` File: ${path_1.default.basename(zipFilePath)}`));
console.log(chalk_1.default.blue(` Response status: ${res.status} ${res.statusText}`));
const lines = res.data.logEntries || [];
console.log(chalk_1.default.blue(` Deployment log entries (${lines.length} lines):`));
lines.forEach((line) => {
console.log(chalk_1.default.blue(` - [${line.type} ${line.timestamp}] ${line.message} `));
});
}
spinner.succeed("Successfully deployed");
console.log(chalk_1.default.green(`${data.agentName} deployed successfully!`));
console.log(chalk_1.default.cyan(`📍 Instance: ${data.machineName}`));
console.log(chalk_1.default.cyan(`🤖 Agent: ${name} (${agentId})`));
console.log(chalk_1.default.cyan(`⚙️ Entry: ${resolvedEntry}`));
console.log(chalk_1.default.cyan(`🔄 Process: ${res.data.processName}`));
}
catch (error) {
spinner.fail(`Failed to deploy ${data.agentName.toLowerCase()} with Error: ${error.message || "Unknown error"}`);
}
}
}), () => {
apis = (0, apiUtils_1.createApis)();
});
}
catch (error) {
if (error.message && error.message.includes("Authentication")) {
console.error(chalk_1.default.red(error.message));
}
else if (error.response) {
console.error(chalk_1.default.red(`API Error (${error.response.status}): ${((_a = error.response.data) === null || _a === void 0 ? void 0 : _a.message) || "Unknown error"}`));
if (error.response.data) {
console.error(chalk_1.default.red(`Error Data: ${JSON.stringify(error.response.data, null, 2)}`));
}
}
else {
console.error(chalk_1.default.red("Error:"), error.message || "Unknown error");
}
}
}));
}
//# sourceMappingURL=deploy.js.map