adpa-enterprise-framework-automation
Version:
Modular, standards-compliant Node.js/TypeScript automation framework for enterprise requirements, project, and data management. Provides CLI and API for BABOK v3, PMBOK 7th Edition, and DMBOK 2.0 (in progress). Production-ready Express.js API with TypeSpe
332 lines (330 loc) • 12.6 kB
JavaScript
/**
* Prompt Manager for AI Document Generation
*
* Manages prompt selection, context building, and prompt customization
* for tailored AI content generation across different document types.
*
* @version 1.0.0
* @author Requirements Gathering Agent Team
* @created 2024
*
* Key Features:
* - Intelligent prompt selection based on document type
* - Context-aware prompt building
* - Dynamic prompt customization
* - Performance optimization and caching
*
* @filepath src/modules/ai/prompts/PromptManager.ts
*/
import { PromptRegistry } from './PromptRegistry.js';
/**
* Manages AI prompt selection, building, and optimization
*/
export class PromptManager {
static instance;
promptRegistry;
contextCache = new Map();
promptMetrics = new Map();
constructor() {
this.promptRegistry = PromptRegistry.getInstance();
}
static getInstance() {
if (!PromptManager.instance) {
PromptManager.instance = new PromptManager();
}
return PromptManager.instance;
}
/**
* Build complete prompt for document generation
*/
async buildPromptForDocument(documentType, projectContext, options = {}) {
const startTime = Date.now();
try {
// Select appropriate prompt template
const template = await this.selectPromptTemplate({
documentType,
maxTokens: options.maxContextLength
});
if (!template) {
console.warn(`No prompt template found for document type: ${documentType}`);
return null;
}
// Build context
const contextStartTime = Date.now();
const context = await this.buildPromptContext(documentType, projectContext, options);
const contextBuildTime = Date.now() - contextStartTime;
// Build final prompt
const promptResult = this.promptRegistry.buildPrompt(template.id, context);
if (!promptResult) {
console.warn(`Failed to build prompt for template: ${template.id}`);
return null;
}
// Create messages
const messages = [
{ role: 'system', content: promptResult.systemPrompt },
{ role: 'user', content: promptResult.userPrompt }
];
// Calculate metrics
const totalTime = Date.now() - startTime;
const metrics = {
selectionTime: totalTime - contextBuildTime,
contextBuildTime,
promptLength: promptResult.systemPrompt.length + promptResult.userPrompt.length,
contextSources: this.countContextSources(context),
templateVersion: template.version
};
// Cache metrics for analysis
this.promptMetrics.set(`${documentType}-${Date.now()}`, metrics);
return { messages, metrics };
}
catch (error) {
console.error(`Error building prompt for document type ${documentType}:`, error);
return null;
}
}
/**
* Select the best prompt template for given criteria
*/
async selectPromptTemplate(criteria) {
// First try exact document type match
let template = this.promptRegistry.getPromptByDocumentType(criteria.documentType);
if (template) {
return template;
}
// Try category-based selection
if (criteria.category) {
const categoryPrompts = this.promptRegistry.getPromptsByCategory(criteria.category);
if (categoryPrompts.length > 0) {
return this.selectBestPromptFromCandidates(categoryPrompts, criteria);
}
}
// Try tag-based selection
if (criteria.requiredTags && criteria.requiredTags.length > 0) {
const tagPrompts = this.promptRegistry.searchPromptsByTags(criteria.requiredTags);
if (tagPrompts.length > 0) {
return this.selectBestPromptFromCandidates(tagPrompts, criteria);
}
}
// Fallback to generic prompt if available
return this.getGenericPromptForDocumentType(criteria.documentType);
}
/**
* Build comprehensive context for prompt
*/
async buildPromptContext(documentType, projectContext, options) {
const context = {
projectContext
};
// Add related documents context if requested
if (options.includeRelatedContext) {
context.relatedDocuments = await this.getRelatedDocumentsContext(documentType);
}
// Add stakeholder context
context.stakeholders = await this.getStakeholderContext(projectContext);
// Add business domain context
context.businessDomain = await this.getBusinessDomainContext(projectContext);
// Add technical context
context.technicalContext = await this.getTechnicalContext(projectContext);
// Apply custom variables
if (options.customVariables) {
Object.assign(context, options.customVariables);
}
return context;
}
/**
* Select best prompt from candidates based on criteria
*/
selectBestPromptFromCandidates(candidates, criteria) {
if (candidates.length === 0)
return null;
if (candidates.length === 1)
return candidates[0];
// Score each candidate
const scoredCandidates = candidates.map(candidate => ({
template: candidate,
score: this.scorePromptTemplate(candidate, criteria)
}));
// Sort by score (highest first)
scoredCandidates.sort((a, b) => b.score - a.score);
return scoredCandidates[0].template;
}
/**
* Score a prompt template based on selection criteria
*/
scorePromptTemplate(template, criteria) {
let score = 0;
// Document type exact match (highest priority)
if (template.documentType === criteria.documentType) {
score += 100;
}
// Category match
if (criteria.category && template.category === criteria.category) {
score += 50;
}
// Required tags match
if (criteria.requiredTags) {
const matchedRequiredTags = criteria.requiredTags.filter(tag => template.tags.includes(tag)).length;
score += matchedRequiredTags * 20;
}
// Preferred tags match
if (criteria.preferredTags) {
const matchedPreferredTags = criteria.preferredTags.filter(tag => template.tags.includes(tag)).length;
score += matchedPreferredTags * 10;
}
// Priority score
score += template.priority * 5;
// Token limit compliance
if (criteria.maxTokens && template.maxTokens <= criteria.maxTokens) {
score += 15;
}
// Recency bonus (newer templates get slight preference)
const daysSinceUpdate = (Date.now() - template.lastUpdated.getTime()) / (1000 * 60 * 60 * 24);
if (daysSinceUpdate < 30) {
score += 5;
}
return score;
}
/**
* Get generic prompt for document type as fallback
*/
getGenericPromptForDocumentType(documentType) {
// Create a basic generic prompt template
return {
id: `generic-${documentType}`,
documentType,
category: 'generic',
systemPrompt: `You are an expert business analyst and technical writer. Create comprehensive, professional documentation that follows industry best practices and standards.`,
userPromptTemplate: `Based on the project context below, create a detailed {{documentType}} document:
Project Context:
{{projectContext}}
Ensure your document is:
- Well-structured and professionally formatted
- Comprehensive and actionable
- Aligned with industry best practices
- Tailored to the specific project needs
- Clear and easy to understand`,
structureInstructions: 'Structure your document with clear sections, headings, and logical flow.',
qualityCriteria: 'Ensure high quality, accuracy, and professional presentation.',
maxTokens: 2000,
priority: 1,
tags: ['generic'],
version: '1.0.0',
lastUpdated: new Date()
};
}
/**
* Get related documents context
*/
async getRelatedDocumentsContext(documentType) {
// This would integrate with the context manager to get related documents
// For now, return empty array
return [];
}
/**
* Extract stakeholder context from project context
*/
async getStakeholderContext(projectContext) {
// Extract stakeholder information from project context
const stakeholderKeywords = ['stakeholder', 'user', 'customer', 'sponsor', 'team', 'role'];
const lines = projectContext.split('\n');
const stakeholderLines = lines.filter(line => stakeholderKeywords.some(keyword => line.toLowerCase().includes(keyword)));
return stakeholderLines.join('\n');
}
/**
* Extract business domain context
*/
async getBusinessDomainContext(projectContext) {
// Extract business domain information
const businessKeywords = ['business', 'domain', 'industry', 'market', 'customer', 'revenue'];
const lines = projectContext.split('\n');
const businessLines = lines.filter(line => businessKeywords.some(keyword => line.toLowerCase().includes(keyword)));
return businessLines.join('\n');
}
/**
* Extract technical context
*/
async getTechnicalContext(projectContext) {
// Extract technical information
const techKeywords = ['technology', 'technical', 'system', 'architecture', 'platform', 'api', 'database'];
const lines = projectContext.split('\n');
const techLines = lines.filter(line => techKeywords.some(keyword => line.toLowerCase().includes(keyword)));
return techLines.join('\n');
}
/**
* Count context sources used
*/
countContextSources(context) {
let count = 0;
if (context.projectContext)
count++;
if (context.documentContext)
count++;
if (context.relatedDocuments && context.relatedDocuments.length > 0)
count++;
if (context.stakeholders)
count++;
if (context.businessDomain)
count++;
if (context.technicalContext)
count++;
return count;
}
/**
* Get prompt performance metrics
*/
getPromptMetrics(documentType) {
if (documentType) {
return Array.from(this.promptMetrics.entries())
.filter(([key]) => key.startsWith(documentType))
.map(([, metrics]) => metrics);
}
return Array.from(this.promptMetrics.values());
}
/**
* Clear metrics cache
*/
clearMetrics() {
this.promptMetrics.clear();
}
/**
* Get available document types
*/
getAvailableDocumentTypes() {
const categories = this.promptRegistry.getCategories();
const documentTypes = [];
for (const category of categories) {
const prompts = this.promptRegistry.getPromptsByCategory(category);
for (const prompt of prompts) {
if (!documentTypes.includes(prompt.documentType)) {
documentTypes.push(prompt.documentType);
}
}
}
return documentTypes.sort();
}
/**
* Validate prompt template
*/
validatePromptTemplate(template) {
const errors = [];
if (!template.id)
errors.push('Template ID is required');
if (!template.documentType)
errors.push('Document type is required');
if (!template.category)
errors.push('Category is required');
if (!template.systemPrompt)
errors.push('System prompt is required');
if (!template.userPromptTemplate)
errors.push('User prompt template is required');
if (template.maxTokens <= 0)
errors.push('Max tokens must be positive');
if (template.priority < 0)
errors.push('Priority must be non-negative');
return {
isValid: errors.length === 0,
errors
};
}
}
//# sourceMappingURL=PromptManager.js.map