UNPKG

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
#!/usr/bin/env node 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