Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,11 @@ elevenlabs auth login
elevenlabs auth logout
elevenlabs auth whoami

# Create agent
elevenlabs agents add "Agent Name" [--template customer-service]
# Create agent from template
elevenlabs agents add "Agent Name" [--template customer-service] [--output-path path]

# Create agent from existing config file
elevenlabs agents add [name] --from-file existing-config.json [--output-path path]

# Create webhook tool
elevenlabs tools add-webhook "Tool Name" [--config-path path]
Expand Down Expand Up @@ -277,7 +280,7 @@ elevenlabs agents add "My Agent" --template assistant
elevenlabs agents push
```

**Import Existing:**
**Import Existing from ElevenLabs:**

```bash
elevenlabs agents init
Expand All @@ -286,6 +289,21 @@ elevenlabs agents pull
elevenlabs agents push
```

**Create Agent from Local Config File:**

```bash
# You have an existing agent config file (e.g., my-template.json)
# Import it and register it with ElevenLabs
elevenlabs agents init
elevenlabs auth login
elevenlabs agents add --from-file my-template.json
# This will:
# - Upload the agent to ElevenLabs
# - Get an agent ID
# - Register it in agents.json
# - Save a copy to agent_configs/
```

**Import and Use Tools:**

```bash
Expand Down
77 changes: 58 additions & 19 deletions src/agents/commands/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,22 @@ interface AgentDefinition {
}

interface AddOptions {
configPath?: string;
outputPath?: string;
template?: string;
fromFile?: string;
}

export function createAddCommand(): Command {
return new Command('add')
.description('Add a new agent - creates config, uploads to ElevenLabs, and saves ID')
.argument('[name]', 'Name of the agent to create')
.option('--config-path <path>', 'Custom config path (optional)')
.option('--template <template>', 'Template type to use')
.option('--output-path <path>', 'Custom output path for the config file (optional)')
.option('--template <template>', 'Template type to use (default, minimal, voice-only, text-only, customer-service, assistant)')
.option('--from-file <path>', 'Create agent from an existing config file')
.option('--no-ui', 'Disable interactive UI')
.action(async (name: string | undefined, options: AddOptions & { ui: boolean }) => {
try {
if (options.ui !== false && !options.configPath) {
if (options.ui !== false && !options.outputPath && !options.fromFile) {
// Use Ink UI for agent creation
const { waitUntilExit } = render(
React.createElement(AddAgentView, {
Expand All @@ -48,9 +50,15 @@ export function createAddCommand(): Command {
return;
}

// Non-UI path requires name to be provided
if (!name) {
console.error('Error: Agent name is required when using --no-ui or --config-path');
// Validate options
if (options.fromFile && options.template) {
console.error('Error: Cannot use both --from-file and --template options together');
process.exit(1);
}

// Non-UI path requires name to be provided (or --from-file with name in the file)
if (!name && !options.fromFile) {
console.error('Error: Agent name is required when using --no-ui or --output-path');
process.exit(1);
}

Expand All @@ -64,17 +72,43 @@ export function createAddCommand(): Command {
// Load existing config
const agentsConfig = await readConfig<AgentsConfig>(agentsConfigPath);

// Create agent config using template (in memory first)
// Create or load agent config
let agentConfig: AgentConfig;
try {
agentConfig = getTemplateByName(name, options.template || 'default');
} catch (error) {
console.error(`${error}`);
process.exit(1);
let agentName: string;

if (options.fromFile) {
// Load config from existing file
console.log(`Loading agent config from '${options.fromFile}'...`);
try {
agentConfig = await readConfig<AgentConfig>(options.fromFile);
// Use provided name or name from config file
agentName = name || agentConfig.name;
// Override the name in config if a name was explicitly provided
if (name) {
agentConfig.name = name;
}
console.log(`Loaded config for agent: ${agentName}`);
} catch (error) {
console.error(`Error reading config file '${options.fromFile}': ${error}`);
process.exit(1);
}
} else {
// Create agent config using template (in memory first)
if (!name) {
console.error('Error: Agent name is required when using templates');
process.exit(1);
}
agentName = name;
try {
agentConfig = getTemplateByName(name, options.template || 'default');
} catch (error) {
console.error(`${error}`);
process.exit(1);
}
}

// Create agent in ElevenLabs first to get ID
console.log(`Creating agent '${name}' in ElevenLabs...`);
console.log(`Creating agent '${agentName}' in ElevenLabs...`);

const client = await getElevenLabsClient();

Expand All @@ -87,7 +121,7 @@ export function createAddCommand(): Command {
// Create new agent
const agentId = await createAgentApi(
client,
name,
agentName,
conversationConfig,
platformSettings,
workflow,
Expand All @@ -97,17 +131,22 @@ export function createAddCommand(): Command {
console.log(`Created agent in ElevenLabs with ID: ${agentId}`);

// Generate config path using agent name (or custom path if provided)
let configPath = options.configPath;
let configPath = options.outputPath;
if (!configPath) {
configPath = await generateUniqueFilename('agent_configs', name);
configPath = await generateUniqueFilename('agent_configs', agentName);
}

// Create config directory and file
const configFilePath = path.resolve(configPath);
await fs.ensureDir(path.dirname(configFilePath));

await writeConfig(configFilePath, agentConfig);
console.log(`Created config file: ${configPath} (template: ${options.template || 'default'})`);

if (options.fromFile) {
console.log(`Created config file: ${configPath} (from: ${options.fromFile})`);
} else {
console.log(`Created config file: ${configPath} (template: ${options.template || 'default'})`);
}

// Store agent ID in index file
const newAgent: AgentDefinition = {
Expand All @@ -118,7 +157,7 @@ export function createAddCommand(): Command {

// Save updated agents.json
await writeConfig(agentsConfigPath, agentsConfig);
console.log(`Added agent '${name}' to agents.json`);
console.log(`Added agent '${agentName}' to agents.json`);

console.log(`Edit ${configPath} to customize your agent, then run 'elevenlabs agents push' to update`);

Expand Down
7 changes: 4 additions & 3 deletions src/agents/ui/AgentsHelpView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ const commands: Command[] = [
],
},
{
name: "add <name>",
name: "add [name]",
description: "Create a new agent and push to remote",
options: [
{ flag: "--config-path <path>", description: "Custom config path" },
{ flag: "--template <template>", description: "Template type to use (default: 'default')" },
{ flag: "--output-path <path>", description: "Custom output path for config file" },
{ flag: "--from-file <path>", description: "Create agent from existing config file" },
{ flag: "--template <template>", description: "Template type to use (default, minimal, voice-only, text-only, customer-service, assistant)" },
],
},
{
Expand Down
Loading