UNPKG

@nestbox-ai/cli

Version:

The cli tools that helps developers to build agents

193 lines (170 loc) 7.38 kB
import { Command } from "commander"; import { withTokenRefresh } from "../../utils/error"; import chalk from "chalk"; import ora from "ora"; import Table from "cli-table3"; import fs from "fs"; import yaml from 'js-yaml'; import { AgentYamlConfig } from "../../types/agentYaml"; import { userData } from "../../utils/user"; import { createAgent } from "./create"; import { createApis } from "./apiUtils"; export function registerCreateFromYamlCommand(agentCommand: Command): void { agentCommand .command("create [firstArg] [secondArg]") .description("Create multiple agents from a YAML configuration file") .option("--project <projectId>", "Project ID (defaults to the current project)") .action(async (firstArg: string, secondArg: any, options: any) => { try { let apis = createApis(); // Determine which argument is the YAML file path let yamlFilePath: string; if (firstArg === 'file' && secondArg) { yamlFilePath = secondArg; } else if (firstArg) { yamlFilePath = firstArg; if (typeof secondArg === 'object' && !options) { options = secondArg; } } else { console.error(chalk.red("Missing YAML file path. Usage: nestbox agent create <yamlFile> OR nestbox agent create file <yamlFile>")); return; } // Check if file exists if (!fs.existsSync(yamlFilePath)) { console.error(chalk.red(`YAML file not found: ${yamlFilePath}`)); return; } // Read and parse the YAML file const spinner = ora(`Reading agents configuration from ${yamlFilePath}...`).start(); try { const fileContents = fs.readFileSync(yamlFilePath, 'utf8'); const config = yaml.load(fileContents) as AgentYamlConfig; if (!config || !config.agents || !Array.isArray(config.agents)) { spinner.fail("Invalid YAML configuration: Missing 'agents' array"); console.error(chalk.red("The YAML file should contain an 'agents' array with agent configurations")); return; } spinner.succeed(`Found ${config.agents.length} agents in configuration file`); // Process each agent with token refresh support const results = { success: 0, failed: 0, agents: [] as Array<{name: string; success: boolean; message: string}> }; // Get user data once const user = await userData(); for (const agent of config.agents) { if (!agent.name) { console.log(chalk.yellow("Skipping agent with no name defined")); results.failed++; results.agents.push({ name: "unnamed", success: false, message: "Name is required" }); continue; } let agentType = agent.type || "CHAT"; const resourceType = agentType === "AGENT" ? "Agent" : "Chatbot"; const agentSpinner = ora(`Creating ${resourceType.toLowerCase()} '${agent.name}'...`).start(); try { // Create agent with token refresh support await withTokenRefresh( async () => { // Map YAML config to createAgent options const createOptions = { ...options, goal: agent.goal || "No goal specified", modelBaseId: agent.modelBaseId || "", instanceIP: agent.instanceIP || "localhost", machineInstanceId: agent.machineInstanceId || 1, machineManifestId: agent.machineManifestId || "default", machineName: agent.machineName || `agent-${agent.name.toLowerCase()}`, type: agentType, userId: user.id, parameters: agent.parameters ? agent.parameters.map((p: any) => { return { name: p.name || "unnamed", description: p.description || "", default: p.default || "", isUserParam: p.isUserParam !== undefined ? p.isUserParam : true }; }) : [] }; await createAgent(agent.name, createOptions, apis.agentsApi, apis.projectsApi); }, () => { apis = createApis(); } ); agentSpinner.stop(); results.success++; results.agents.push({ name: agent.name, success: true, message: `Created successfully` }); } catch (error: any) { agentSpinner.fail(`Failed to create ${resourceType.toLowerCase()} '${agent.name}'`); console.error(chalk.red(`Error: ${error.message}`)); results.failed++; results.agents.push({ name: agent.name, success: false, message: error.message }); } } // Final summary console.log(chalk.blue("\nResource creation summary:")); const table = new Table({ head: [ chalk.white.bold("Name"), chalk.white.bold("Type"), chalk.white.bold("Status"), chalk.white.bold("Message"), ], style: { head: [], border: [], }, }); results.agents.forEach((agent, index) => { const agentConfig = config.agents.find(a => a.name === agent.name) || config.agents[index]; const agentType = agentConfig?.type || "CHAT"; const resourceType = agentType === "AGENT" ? "Agent" : "Chatbot"; table.push([ agent.name, resourceType, agent.success ? chalk.green("Success") : chalk.red("Failed"), agent.message ]); }); console.log(table.toString()); console.log(`\nTotal: ${results.success + results.failed}, Successful: ${results.success}, Failed: ${results.failed}`); } catch (error: any) { spinner.fail("Failed to process YAML file"); if (error.code === 'ENOENT') { console.error(chalk.red(`File not found: ${yamlFilePath}`)); } else if (error.name === 'YAMLException') { console.error(chalk.red(`Invalid YAML format: ${error.message}`)); } else { console.error( chalk.red("Error:"), error.message || "Unknown error" ); } } } catch (error: any) { if (error.message && error.message.includes('Authentication')) { console.error(chalk.red(error.message)); } else { console.error( chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error" ); } } }); }