promptforge
Version:
Adaptive Prompt Intelligence & Orchestration SDK - Manage, optimize, and serve prompts for LLMs with versioning, feedback loops, and multi-provider support
291 lines (279 loc) • 10.7 kB
JavaScript
import { Command } from 'commander';
import chalk from 'chalk';
import ora from 'ora';
import fs from 'fs/promises';
import path from 'path';
import { PromptForge } from '../core/forge.js';
import { ConfigLoader } from '../utils/config-loader.js';
import { VERSION } from '../index.js';
const program = new Command();
program
.name('forge')
.description('PromptForge CLI - Adaptive Prompt Intelligence & Orchestration')
.version(VERSION);
/**
* Initialize a new PromptForge project
*/
program
.command('init')
.argument('[project-name]', 'Project name', 'my-promptforge-project')
.description('Initialize a new PromptForge project')
.action(async (projectName) => {
const spinner = ora('Creating PromptForge project...').start();
try {
// Create project directory
const projectDir = path.join(process.cwd(), projectName);
await fs.mkdir(projectDir, { recursive: true });
// Create subdirectories
await fs.mkdir(path.join(projectDir, 'prompts'), { recursive: true });
await fs.mkdir(path.join(projectDir, 'datasets'), { recursive: true });
await fs.mkdir(path.join(projectDir, 'migrations'), { recursive: true });
// Create config file
const config = ConfigLoader.createDefault(projectName);
await ConfigLoader.saveToFile(config, path.join(projectDir, 'promptforge.json'));
// Create .env file
const envContent = `# LLM Provider API Keys
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
GOOGLE_API_KEY=
MISTRAL_API_KEY=
# Database
DATABASE_URL=postgresql://localhost:5432/promptforge
# Redis
REDIS_URL=redis://localhost:6379
# Pinecone
PINECONE_API_KEY=
PINECONE_ENVIRONMENT=us-west1-gcp
PINECONE_INDEX_NAME=promptforge-embeddings
`;
await fs.writeFile(path.join(projectDir, '.env'), envContent);
// Create sample prompt
const samplePrompt = `name: greeting
description: A friendly greeting prompt
variables:
- name
- language
content: |
Hello {{name}}! Welcome to PromptForge.
Please greet me in {{language}}.
systemPrompt: You are a friendly assistant that provides warm greetings.
`;
await fs.writeFile(path.join(projectDir, 'prompts', 'sample.yaml'), samplePrompt);
// Create README
const readme = `# ${projectName}
A PromptForge project for prompt management and optimization.
## Getting Started
1. Install dependencies:
\`\`\`bash
npm install promptforge
\`\`\`
2. Configure your API keys in \`.env\`
3. Create and manage prompts:
\`\`\`bash
forge push greeting --template ./prompts/sample.yaml
forge list
forge execute greeting --input '{"name": "Alice", "language": "Spanish"}'
\`\`\`
## Commands
- \`forge init\` - Initialize project
- \`forge push <name>\` - Create/update prompt
- \`forge list\` - List all prompts
- \`forge execute <name>\` - Execute a prompt
- \`forge eval <name>\` - Evaluate prompt performance
- \`forge optimize\` - Optimize prompts based on feedback
## Documentation
Visit https://github.com/gyash1512/PromptForge for full documentation.
`;
await fs.writeFile(path.join(projectDir, 'README.md'), readme);
spinner.succeed(chalk.green(`✓ Created project: ${projectName}`));
console.log(chalk.cyan('\nNext steps:'));
console.log(` cd ${projectName}`);
console.log(' Configure API keys in .env');
console.log(' forge push greeting --template ./prompts/sample.yaml');
console.log(' forge list');
}
catch (error) {
spinner.fail(chalk.red('Failed to create project'));
console.error(error);
process.exit(1);
}
});
/**
* Push a prompt to the registry
*/
program
.command('push')
.argument('<name>', 'Prompt name')
.option('-t, --template <file>', 'Template file (YAML/JSON)')
.option('-c, --content <text>', 'Prompt content')
.option('-d, --description <text>', 'Prompt description')
.option('--tags <tags>', 'Comma-separated tags')
.option('--owner <owner>', 'Owner name', 'default')
.description('Create or update a prompt')
.action(async (name, options) => {
const spinner = ora('Creating prompt...').start();
try {
const config = await ConfigLoader.loadFromFile('./promptforge.json');
const forge = new PromptForge(config);
let content = options.content;
let templateData;
if (options.template) {
const templateContent = await fs.readFile(options.template, 'utf-8');
const ext = path.extname(options.template);
if (ext === '.yaml' || ext === '.yml') {
const yaml = await import('js-yaml');
templateData = yaml.load(templateContent);
content = templateData.content;
}
else if (ext === '.json') {
templateData = JSON.parse(templateContent);
content = templateData.content;
}
}
if (!content) {
spinner.fail('No content provided. Use --content or --template');
process.exit(1);
}
const prompt = await forge.createPrompt({
name,
content,
description: options.description || templateData?.description,
owner: options.owner,
tags: options.tags ? options.tags.split(',') : templateData?.tags,
template: templateData
? {
variables: templateData.variables,
systemPrompt: templateData.systemPrompt,
}
: undefined,
});
spinner.succeed(chalk.green(`✓ Created prompt: ${prompt.name} (v${prompt.version})`));
console.log(chalk.gray(` ID: ${prompt.id}`));
}
catch (error) {
spinner.fail(chalk.red('Failed to create prompt'));
console.error(error.message);
process.exit(1);
}
});
/**
* List all prompts
*/
program
.command('list')
.option('--owner <owner>', 'Filter by owner')
.option('--tags <tags>', 'Filter by tags (comma-separated)')
.option('--active', 'Show only active prompts')
.description('List all prompts in the registry')
.action(async (options) => {
try {
const config = await ConfigLoader.loadFromFile('./promptforge.json');
const forge = new PromptForge(config);
const prompts = await forge.listPrompts({
owner: options.owner,
tags: options.tags?.split(','),
isActive: options.active ? true : undefined,
});
if (prompts.length === 0) {
console.log(chalk.yellow('No prompts found'));
return;
}
console.log(chalk.bold(`\nFound ${prompts.length} prompt(s):\n`));
prompts.forEach(p => {
console.log(chalk.cyan(`${p.name}`), chalk.gray(`(v${p.version})`));
console.log(chalk.gray(` ID: ${p.id}`));
if (p.description)
console.log(` ${p.description}`);
console.log(chalk.gray(` Owner: ${p.owner} | Usage: ${p.usageCount}`));
if (p.tags.length > 0) {
console.log(chalk.gray(` Tags: ${p.tags.join(', ')}`));
}
console.log();
});
}
catch (error) {
console.error(chalk.red('Error listing prompts:'), error.message);
process.exit(1);
}
});
/**
* Execute a prompt
*/
program
.command('execute')
.argument('<name>', 'Prompt name or ID')
.option('-i, --input <json>', 'Input variables as JSON')
.option('-v, --version <number>', 'Prompt version')
.option('-p, --provider <provider>', 'LLM provider (openai, anthropic, google, mistral, ollama)')
.option('-m, --model <model>', 'Model name')
.option('--no-cache', 'Disable cache')
.description('Execute a prompt')
.action(async (name, options) => {
const spinner = ora('Executing prompt...').start();
try {
const config = await ConfigLoader.loadFromFile('./promptforge.json');
const forge = new PromptForge(config);
const input = options.input
? JSON.parse(options.input)
: {};
const result = await forge.executePrompt({
promptName: name,
version: options.version ? parseInt(options.version) : undefined,
input,
llmConfig: options.provider
? {
provider: options.provider,
model: options.model || 'gpt-4o-mini',
temperature: 0.7,
}
: undefined,
useCache: options.cache !== false,
trackMetrics: true,
});
spinner.succeed(chalk.green('✓ Execution completed'));
console.log(chalk.bold('\nOutput:'));
console.log(result.output);
console.log(chalk.gray('\nMetrics:'));
console.log(chalk.gray(` Latency: ${result.metrics.latencyMs}ms`));
console.log(chalk.gray(` Tokens: ${result.metrics.totalTokens} (in: ${result.metrics.inputTokens}, out: ${result.metrics.outputTokens})`));
console.log(chalk.gray(` Cost: $${result.metrics.cost.toFixed(6)}`));
console.log(chalk.gray(` Cached: ${result.cached ? 'Yes' : 'No'}`));
}
catch (error) {
spinner.fail(chalk.red('Execution failed'));
console.error(error.message);
process.exit(1);
}
});
/**
* Get prompt statistics
*/
program
.command('stats')
.description('Show registry statistics')
.action(async () => {
try {
const config = await ConfigLoader.loadFromFile('./promptforge.json');
const forge = new PromptForge(config);
const stats = await forge.getStats();
console.log(chalk.bold('\nPromptForge Statistics:\n'));
console.log(chalk.cyan('Registry:'));
console.log(` Total Prompts: ${stats.totalPrompts}`);
console.log(` Active Prompts: ${stats.activePrompts}`);
console.log(` Total Versions: ${stats.totalVersions}`);
console.log(` Total Usage: ${stats.totalUsage}`);
console.log(chalk.cyan('\nExecutions:'));
console.log(` Total Executions: ${stats.totalExecutions}`);
console.log(` Success Rate: ${(stats.successRate * 100).toFixed(2)}%`);
console.log(` Average Latency: ${stats.averageLatency.toFixed(2)}ms`);
console.log(` Total Cost: $${stats.totalCost.toFixed(4)}`);
console.log();
}
catch (error) {
console.error(chalk.red('Error getting stats:'), error.message);
process.exit(1);
}
});
program.parse();
//# sourceMappingURL=index.js.map