UNPKG

promptforge

Version:

Adaptive Prompt Intelligence & Orchestration SDK - Manage, optimize, and serve prompts for LLMs with versioning, feedback loops, and multi-provider support

285 lines 9.38 kB
import { v4 as uuidv4 } from 'uuid'; import { PromptMetadataSchema, PromptTemplateSchema, } from '../types.js'; export class PromptRegistry { prompts; versions; templates; nameToIdMap; config; constructor(config = {}) { this.prompts = new Map(); this.versions = new Map(); this.templates = new Map(); this.nameToIdMap = new Map(); this.config = { storageBackend: 'memory', enableVersioning: true, maxVersionsPerPrompt: 50, ...config, }; } /** * Create a new prompt with metadata and optional template */ async createPrompt(request) { const promptId = uuidv4(); const now = new Date(); // Check if prompt name already exists if (this.nameToIdMap.has(request.name)) { throw new Error(`Prompt with name "${request.name}" already exists`); } const metadata = { id: promptId, name: request.name, description: request.description, owner: request.owner, tags: request.tags || [], createdAt: now, updatedAt: now, version: 1, isActive: true, usageCount: 0, provider: request.provider, }; // Validate metadata const validatedMetadata = PromptMetadataSchema.parse(metadata); // Store prompt metadata this.prompts.set(promptId, validatedMetadata); this.nameToIdMap.set(request.name, promptId); // Create first version const version = { id: uuidv4(), promptId, version: 1, content: request.content, metadata: validatedMetadata, }; // Store version this.versions.set(promptId, [version]); // Create template if provided if (request.template) { const template = { id: uuidv4(), promptId, content: request.content, variables: request.template.variables || this.extractVariables(request.content), systemPrompt: request.template.systemPrompt, format: request.template.format || 'text', }; const validatedTemplate = PromptTemplateSchema.parse(template); this.templates.set(promptId, validatedTemplate); version.template = validatedTemplate; } return validatedMetadata; } /** * Update an existing prompt and create a new version */ async updatePrompt(promptId, content, metadata) { const currentMetadata = this.prompts.get(promptId); if (!currentMetadata) { throw new Error(`Prompt with ID "${promptId}" not found`); } const versions = this.versions.get(promptId) || []; const newVersionNumber = currentMetadata.version + 1; // Check max versions limit if (versions.length >= this.config.maxVersionsPerPrompt) { // Remove oldest version versions.shift(); } const now = new Date(); const updatedMetadata = { ...currentMetadata, ...metadata, version: newVersionNumber, updatedAt: now, parentVersion: currentMetadata.version, }; // Update stored metadata this.prompts.set(promptId, updatedMetadata); // Create new version const newVersion = { id: uuidv4(), promptId, version: newVersionNumber, content, metadata: updatedMetadata, }; // Update template if exists const template = this.templates.get(promptId); if (template) { const updatedTemplate = { ...template, content, variables: this.extractVariables(content), }; this.templates.set(promptId, updatedTemplate); newVersion.template = updatedTemplate; } versions.push(newVersion); this.versions.set(promptId, versions); return newVersion; } /** * Get prompt metadata by ID or name */ async getPrompt(idOrName) { // Try by ID first let prompt = this.prompts.get(idOrName); // If not found, try by name if (!prompt) { const id = this.nameToIdMap.get(idOrName); if (id) { prompt = this.prompts.get(id); } } return prompt; } /** * Get specific version of a prompt */ async getPromptVersion(promptId, version) { const versions = this.versions.get(promptId); if (!versions || versions.length === 0) { return undefined; } if (version === undefined) { // Return latest version return versions[versions.length - 1]; } return versions.find(v => v.version === version); } /** * Get all versions of a prompt */ async getPromptVersions(promptId) { return this.versions.get(promptId) || []; } /** * Get prompt template */ async getTemplate(promptId) { return this.templates.get(promptId); } /** * List all prompts with optional filtering */ async listPrompts(filter) { let prompts = Array.from(this.prompts.values()); if (filter) { prompts = prompts.filter(p => { if (filter.owner && p.owner !== filter.owner) return false; if (filter.isActive !== undefined && p.isActive !== filter.isActive) return false; if (filter.tags && filter.tags.length > 0) { const hasAllTags = filter.tags.every(tag => p.tags.includes(tag)); if (!hasAllTags) return false; } return true; }); } return prompts; } /** * Delete a prompt and all its versions */ async deletePrompt(promptId) { const metadata = this.prompts.get(promptId); if (!metadata) { return false; } // Remove from name map this.nameToIdMap.delete(metadata.name); // Remove metadata this.prompts.delete(promptId); // Remove versions this.versions.delete(promptId); // Remove template this.templates.delete(promptId); return true; } /** * Deactivate a prompt (soft delete) */ async deactivatePrompt(promptId) { const metadata = this.prompts.get(promptId); if (!metadata) { return false; } metadata.isActive = false; metadata.updatedAt = new Date(); this.prompts.set(promptId, metadata); return true; } /** * Increment usage count for a prompt */ async incrementUsage(promptId) { const metadata = this.prompts.get(promptId); if (metadata) { metadata.usageCount += 1; this.prompts.set(promptId, metadata); } } /** * Update average score for a prompt */ async updateScore(promptId, score) { const metadata = this.prompts.get(promptId); if (metadata) { if (metadata.averageScore === undefined) { metadata.averageScore = score; } else { // Calculate running average const totalScore = metadata.averageScore * metadata.usageCount; metadata.averageScore = (totalScore + score) / (metadata.usageCount + 1); } this.prompts.set(promptId, metadata); } } /** * Search prompts by content similarity (semantic search) */ async searchPrompts(query, limit = 10) { const prompts = Array.from(this.prompts.values()); // Simple text search for now (will be enhanced with embeddings) const results = prompts.filter(p => { const searchText = `${p.name} ${p.description || ''} ${p.tags.join(' ')}`.toLowerCase(); return searchText.includes(query.toLowerCase()); }); return results.slice(0, limit); } /** * Extract template variables from content */ extractVariables(content) { const variablePattern = /\{\{(\w+)\}\}/g; const variables = []; let match; while ((match = variablePattern.exec(content)) !== null) { if (!variables.includes(match[1])) { variables.push(match[1]); } } return variables; } /** * Get registry statistics */ async getStats() { const prompts = Array.from(this.prompts.values()); const activePrompts = prompts.filter(p => p.isActive); const totalVersions = Array.from(this.versions.values()).reduce((sum, versions) => sum + versions.length, 0); const totalUsage = prompts.reduce((sum, p) => sum + p.usageCount, 0); return { totalPrompts: prompts.length, activePrompts: activePrompts.length, totalVersions, totalUsage, }; } } //# sourceMappingURL=registry.js.map