PromptEnhancer.js•19.4 kB
"use strict";
/**
* PromptEnhancer
*
* Intelligently enhances prompts with relevant context:
* - Combines original prompt with adaptive context
* - Filters context based on task type and focus area
* - Formats enhanced prompts for optimal LLM performance
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PromptEnhancer = void 0;
const TaskTracker_1 = require("../tracker/TaskTracker");
const Logger_1 = __importDefault(require("../utils/Logger"));
class PromptEnhancer {
constructor(projectContextManager, taskTracker, config = {}) {
this.log = Logger_1.default.createChildLogger('PromptEnhancer');
this.projectContextManager = projectContextManager;
this.taskTracker = taskTracker;
this.config = {
maxContextSize: config.maxContextSize || 8000,
includeGitInfo: config.includeGitInfo !== undefined ? config.includeGitInfo : true,
includeDependencies: config.includeDependencies !== undefined ? config.includeDependencies : true,
includePatterns: config.includePatterns !== undefined ? config.includePatterns : true,
contextFormat: config.contextFormat || 'markdown',
};
this.log.info('PromptEnhancer initialized');
}
/**
* Enhance a prompt with relevant context
*/
async enhancePrompt(options) {
const { prompt, taskType, focusFiles, includeFullContext } = options;
this.log.debug('Enhancing prompt');
// Update task tracker with prompt
const taskContext = this.taskTracker.updateFromPrompt(prompt);
// Override task type if provided
if (taskType) {
this.taskTracker.setTaskType(taskType);
}
// Add focus files if provided
if (focusFiles && focusFiles.length > 0) {
this.taskTracker.addRelevantFiles(focusFiles);
}
// Get updated task context
const updatedTaskContext = this.taskTracker.getTaskContext();
// Get project context
const projectContext = await this.projectContextManager.getContext();
// Generate enhanced prompt
const enhancementResult = this.generateEnhancedPrompt(prompt, projectContext, updatedTaskContext, includeFullContext || false);
// Record the enhancement action
this.taskTracker.recordAction('enhance_prompt', updatedTaskContext.relevantFiles, `Enhanced prompt for ${updatedTaskContext.taskType} task`);
return enhancementResult;
}
/**
* Generate enhanced prompt with context
*/
generateEnhancedPrompt(originalPrompt, projectContext, taskContext, includeFullContext) {
// Start with the context section
let contextSection = '';
if (includeFullContext) {
// Full project context for initial analysis or when explicitly requested
contextSection = this.generateFullContext(projectContext);
}
else {
// Task-specific context for ongoing work
contextSection = this.generateTaskSpecificContext(projectContext, taskContext);
}
// Measure context size (rough approximation of tokens)
const contextSize = Math.ceil(contextSection.length / 4);
// Format the enhanced prompt
let enhancedPrompt = '';
if (contextSection.trim().length > 0) {
enhancedPrompt = this.formatEnhancedPrompt(originalPrompt, contextSection);
}
else {
enhancedPrompt = originalPrompt;
}
return {
enhancedPrompt,
originalPrompt,
contextAdded: contextSection.trim().length > 0,
taskType: taskContext.taskType,
focusArea: taskContext.focusArea,
contextSize,
};
}
/**
* Generate full project context
*/
generateFullContext(projectContext) {
this.log.debug('Generating full project context');
let context = '';
// Project overview
context += this.formatSection('Project Overview', [
`Project Name: ${projectContext.projectName}`,
`Frameworks: ${projectContext.frameworks.join(', ') || 'None detected'}`,
]);
// Dependencies (if enabled)
if (this.config.includeDependencies && Object.keys(projectContext.dependencies).length > 0) {
const dependencyList = Object.entries(projectContext.dependencies)
.map(([name, version]) => `${name}: ${version}`)
.join('\n');
context += this.formatSection('Dependencies', [dependencyList]);
}
// File structure
context += this.formatSection('File Structure', [
this.formatFileStructure(projectContext.fileStructure)
]);
// Git information (if enabled)
if (this.config.includeGitInfo && projectContext.recentChanges.length > 0) {
const gitChanges = projectContext.recentChanges
.map(change => `- ${change.message} (by ${change.author} on ${change.date.split('T')[0]})`)
.join('\n');
context += this.formatSection('Recent Changes', [gitChanges]);
const branchInfo = [
`Current Branch: ${projectContext.branchInfo.currentBranch}`,
`All Branches: ${projectContext.branchInfo.branches.join(', ')}`
].join('\n');
context += this.formatSection('Branch Information', [branchInfo]);
}
// Code patterns (if enabled)
if (this.config.includePatterns && projectContext.patterns.length > 0) {
const patternSections = projectContext.patterns.map(pattern => {
return `${pattern.type.toUpperCase()} PATTERN: ${pattern.pattern}\n\nExamples:\n${pattern.examples.map(ex => '```\n' + ex + '\n```').join('\n\n')}`;
}).join('\n\n');
context += this.formatSection('Code Patterns', [patternSections]);
}
return context;
}
/**
* Generate task-specific context
*/
generateTaskSpecificContext(projectContext, taskContext) {
this.log.debug(`Generating task-specific context for ${taskContext.taskType} task in ${taskContext.focusArea} area`);
let context = '';
// Task overview
context += this.formatSection('Task Context', [
`Task Type: ${taskContext.taskType}`,
`Focus Area: ${taskContext.focusArea}`,
]);
// Include frameworks and project type info for all tasks
context += this.formatSection('Project Type', [
`Frameworks: ${projectContext.frameworks.join(', ') || 'None detected'}`,
]);
// Add task-specific context based on task type
switch (taskContext.taskType) {
case TaskTracker_1.TaskType.CREATION:
context += this.generateCreationTaskContext(projectContext, taskContext);
break;
case TaskTracker_1.TaskType.DEBUGGING:
context += this.generateDebuggingTaskContext(projectContext, taskContext);
break;
case TaskTracker_1.TaskType.REFACTORING:
context += this.generateRefactoringTaskContext(projectContext, taskContext);
break;
case TaskTracker_1.TaskType.STYLING:
context += this.generateStylingTaskContext(projectContext, taskContext);
break;
case TaskTracker_1.TaskType.API:
context += this.generateApiTaskContext(projectContext, taskContext);
break;
default:
// For general tasks or other types, include minimal context
context += this.generateGeneralTaskContext(projectContext, taskContext);
break;
}
// Add relevant files info
if (taskContext.relevantFiles.length > 0) {
context += this.formatSection('Relevant Files', [
taskContext.relevantFiles.join('\n')
]);
}
// Add recent actions if available
if (taskContext.recentActions.length > 0) {
const recentActionsText = taskContext.recentActions
.map(action => {
const filesText = action.files && action.files.length > 0
? ` (files: ${action.files.join(', ')})`
: '';
return `- ${action.description}${filesText}`;
})
.join('\n');
context += this.formatSection('Recent Actions', [recentActionsText]);
}
return context;
}
/**
* Generate context for creation tasks
*/
generateCreationTaskContext(projectContext, taskContext) {
let context = '';
// For creation tasks, include:
// 1. Dependencies (for setup)
if (this.config.includeDependencies) {
const relevantDeps = this.filterRelevantDependencies(projectContext, taskContext.focusArea);
if (Object.keys(relevantDeps).length > 0) {
const depsText = Object.entries(relevantDeps)
.map(([name, version]) => `${name}: ${version}`)
.join('\n');
context += this.formatSection('Relevant Dependencies', [depsText]);
}
}
// 2. Code patterns for the focus area
if (this.config.includePatterns) {
const relevantPatterns = this.filterRelevantPatterns(projectContext, taskContext.focusArea);
if (relevantPatterns.length > 0) {
const patternsText = relevantPatterns.map(pattern => {
return `${pattern.type.toUpperCase()} PATTERN: ${pattern.pattern}\n\nExample:\n\`\`\`\n${pattern.examples[0] || ''}\n\`\`\``;
}).join('\n\n');
context += this.formatSection('Relevant Patterns', [patternsText]);
}
}
return context;
}
/**
* Generate context for debugging tasks
*/
generateDebuggingTaskContext(projectContext, taskContext) {
let context = '';
// For debugging tasks, include:
// 1. Recent changes that might be related to the bug
if (this.config.includeGitInfo && projectContext.recentChanges.length > 0) {
const recentChangesText = projectContext.recentChanges
.slice(0, 5) // Focus on the most recent changes
.map(change => `- ${change.message} (${change.date.split('T')[0]})`)
.join('\n');
context += this.formatSection('Recent Changes', [recentChangesText]);
}
return context;
}
/**
* Generate context for refactoring tasks
*/
generateRefactoringTaskContext(projectContext, taskContext) {
let context = '';
// For refactoring tasks, include:
// 1. Code patterns that might be relevant
if (this.config.includePatterns) {
const relevantPatterns = this.filterRelevantPatterns(projectContext, taskContext.focusArea);
if (relevantPatterns.length > 0) {
const patternsText = relevantPatterns.map(pattern => {
return `${pattern.type.toUpperCase()}: ${pattern.pattern}\n\nExample:\n\`\`\`\n${pattern.examples[0] || ''}\n\`\`\``;
}).join('\n\n');
context += this.formatSection('Code Patterns', [patternsText]);
}
}
return context;
}
/**
* Generate context for styling tasks
*/
generateStylingTaskContext(projectContext, taskContext) {
let context = '';
// For styling tasks, include:
// 1. Check for styling-related dependencies
if (this.config.includeDependencies) {
const stylingDeps = this.filterStylingDependencies(projectContext);
if (Object.keys(stylingDeps).length > 0) {
const depsText = Object.entries(stylingDeps)
.map(([name, version]) => `${name}: ${version}`)
.join('\n');
context += this.formatSection('Styling Dependencies', [depsText]);
}
}
return context;
}
/**
* Generate context for API tasks
*/
generateApiTaskContext(projectContext, taskContext) {
let context = '';
// For API tasks, include:
// 1. API-related patterns
if (this.config.includePatterns) {
const apiPatterns = projectContext.patterns.filter(pattern => pattern.type === 'route' || pattern.pattern.toLowerCase().includes('api'));
if (apiPatterns.length > 0) {
const patternsText = apiPatterns.map(pattern => {
return `${pattern.type.toUpperCase()}: ${pattern.pattern}\n\nExample:\n\`\`\`\n${pattern.examples[0] || ''}\n\`\`\``;
}).join('\n\n');
context += this.formatSection('API Patterns', [patternsText]);
}
}
return context;
}
/**
* Generate context for general tasks
*/
generateGeneralTaskContext(projectContext, taskContext) {
// For general tasks, minimal context is already provided by the main method
return '';
}
/**
* Filter dependencies relevant to the focus area
*/
filterRelevantDependencies(projectContext, focusArea) {
const deps = { ...projectContext.dependencies };
const filtered = {};
// Keywords for different focus areas
const keywords = {
[TaskTracker_1.FocusArea.FRONTEND]: ['react', 'vue', 'angular', 'svelte', 'component', 'ui', 'dom'],
[TaskTracker_1.FocusArea.BACKEND]: ['express', 'koa', 'nest', 'node', 'server', 'api'],
[TaskTracker_1.FocusArea.DATABASE]: ['mongo', 'postgres', 'mysql', 'sqlite', 'prisma', 'sequelize', 'typeorm'],
[TaskTracker_1.FocusArea.STYLING]: ['css', 'sass', 'less', 'tailwind', 'styled', 'emotion', 'bootstrap'],
[TaskTracker_1.FocusArea.TESTING]: ['jest', 'mocha', 'chai', 'cypress', 'testing', 'test'],
[TaskTracker_1.FocusArea.STATE]: ['redux', 'mobx', 'zustand', 'recoil', 'context', 'state'],
[TaskTracker_1.FocusArea.DEPLOYMENT]: ['docker', 'kubernetes', 'aws', 'azure', 'vercel', 'netlify'],
[TaskTracker_1.FocusArea.GENERAL]: [],
[TaskTracker_1.FocusArea.AUTHENTICATION]: ['auth', 'login', 'register', 'user', 'permission', 'role', 'jwt', 'session'],
[TaskTracker_1.FocusArea.COMPONENTS]: ['component', 'button', 'form', 'input', 'modal', 'menu', 'navigation'],
[TaskTracker_1.FocusArea.ROUTING]: ['route', 'router', 'navigation', 'link', 'path', 'url', 'history', 'params'],
};
// If focus area is general, return a subset of important dependencies
if (focusArea === TaskTracker_1.FocusArea.GENERAL) {
const importantDeps = Object.keys(deps).filter(dep => !dep.startsWith('@types/') &&
!dep.includes('eslint') &&
!dep.includes('prettier')).slice(0, 10);
for (const dep of importantDeps) {
filtered[dep] = deps[dep];
}
return filtered;
}
// Otherwise, filter by focus area keywords
const areaKeywords = keywords[focusArea] || [];
for (const [dep, version] of Object.entries(deps)) {
if (areaKeywords.some(keyword => dep.toLowerCase().includes(keyword))) {
filtered[dep] = version;
}
}
return filtered;
}
/**
* Filter styling-related dependencies
*/
filterStylingDependencies(projectContext) {
const deps = { ...projectContext.dependencies };
const filtered = {};
const stylingKeywords = [
'css', 'sass', 'scss', 'less', 'style', 'styled', 'tailwind', 'bootstrap',
'emotion', 'jss', 'material-ui', 'chakra', 'theme'
];
for (const [dep, version] of Object.entries(deps)) {
if (stylingKeywords.some(keyword => dep.toLowerCase().includes(keyword))) {
filtered[dep] = version;
}
}
return filtered;
}
/**
* Filter patterns relevant to the focus area
*/
filterRelevantPatterns(projectContext, focusArea) {
// Map focus areas to pattern types
const focusToPatternType = {
[TaskTracker_1.FocusArea.FRONTEND]: ['component', 'jsx', 'tsx', 'react', 'vue'],
[TaskTracker_1.FocusArea.BACKEND]: ['route', 'controller', 'service', 'middleware'],
[TaskTracker_1.FocusArea.DATABASE]: ['model', 'schema', 'query', 'database'],
// Remove FocusArea.API which doesn't exist
};
const relevantTypes = focusToPatternType[focusArea] || [];
if (relevantTypes.length === 0) {
// If no specific mapping, return the first 2 patterns (if available)
return projectContext.patterns.slice(0, 2);
}
// Filter patterns by relevance to the focus area
return projectContext.patterns.filter(pattern => relevantTypes.some(type => pattern.type.includes(type) ||
pattern.pattern.toLowerCase().includes(type))).slice(0, 3);
}
/**
* Format file structure into a readable string
*/
formatFileStructure(structure, prefix = '', depth = 0, maxDepth = 3) {
if (depth > maxDepth) {
return `${prefix}...`; // Truncate at max depth
}
let result = '';
// Add directories
for (const [dirName, dirContent] of Object.entries(structure.directories)) {
result += `${prefix}${dirName}/\n`;
result += this.formatFileStructure(dirContent, `${prefix} `, depth + 1, maxDepth);
}
// Add files
for (const file of structure.files) {
result += `${prefix}${file}\n`;
}
return result;
}
/**
* Format a section of the context
*/
formatSection(title, content) {
if (content.every(item => item.trim() === '')) {
return '';
}
switch (this.config.contextFormat) {
case 'markdown':
return `## ${title}\n\n${content.join('\n\n')}\n\n`;
case 'json':
return `"${title}": ${JSON.stringify(content)},\n`;
case 'plain':
default:
return `${title.toUpperCase()}:\n${content.join('\n')}\n\n`;
}
}
/**
* Format the final enhanced prompt
*/
formatEnhancedPrompt(originalPrompt, contextSection) {
switch (this.config.contextFormat) {
case 'markdown':
return `# Context Information\n\n${contextSection}\n# Original Prompt\n\n${originalPrompt}`;
case 'json':
return `{\n"context": {\n${contextSection}},\n"prompt": "${originalPrompt.replace(/"/g, '\\"')}"\n}`;
case 'plain':
default:
return `CONTEXT INFORMATION:\n\n${contextSection}\nORIGINAL PROMPT:\n\n${originalPrompt}`;
}
}
}
exports.PromptEnhancer = PromptEnhancer;
exports.default = PromptEnhancer;
//# sourceMappingURL=PromptEnhancer.js.map