follow xml pattern

This commit is contained in:
2025-03-11 18:40:20 +00:00
parent 3676136692
commit 0ec4e8e2d2
4 changed files with 150 additions and 68 deletions

View File

@@ -31,12 +31,8 @@ export class PromptGenerator {
fileContents.set(filePath, { content, tokens });
}
// Generate the prompt based on settings
if (settings.xmlEditsEnabled) {
return this.generateXMLPrompt(fileContents, settings);
} else {
return this.generatePlainPrompt(fileContents, settings);
}
// Always generate XML prompt
return this.generateXMLPrompt(fileContents, settings);
}
/**
@@ -55,16 +51,7 @@ export class PromptGenerator {
// Add the file to the prompt
promptText += `File: ${fileName}\n`;
// Add line numbers if enabled
if (settings.includeLineNumbers) {
const lines = content.split('\n');
for (let i = 0; i < lines.length; i++) {
promptText += `${i + 1}: ${lines[i]}\n`;
}
} else {
promptText += `${content}\n`;
}
promptText += `${content}\n`;
promptText += '\n';
}
@@ -78,58 +65,156 @@ export class PromptGenerator {
}
/**
* Generate an XML formatted prompt
* Generate an XML formatted prompt following the new schema format
* @param files Map of file paths to content and token counts
* @param settings Settings to apply
* @returns XML formatted prompt
*/
private static generateXMLPrompt(files: Map<string, { content: string; tokens: number }>, settings: PrompterSettings): string {
const xmlParts = ['<?xml version="1.0" encoding="UTF-8"?>', '<prompt>'];
const xmlParts: string[] = [];
// Include XML formatting instructions if enabled
if (settings.includeFormattingInstructions) {
try {
// Get the workspace root path
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri?.fsPath || '';
const formattingInstructionsPath = path.join(workspaceRoot, '..', 'project_management', 'xml_formatting_instructions.xml');
if (fs.existsSync(formattingInstructionsPath)) {
const instructions = fs.readFileSync(formattingInstructionsPath, 'utf8');
xmlParts.push(instructions);
}
} catch (error) {
console.error('Error reading XML formatting instructions:', error);
}
}
// Add files section
xmlParts.push(' <files>');
// Generate file map section if enabled in settings
if (settings.includeFileMap) {
xmlParts.push('<file_map>');
// Get the workspace root path
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri?.fsPath || '';
xmlParts.push(workspaceRoot);
// Create a tree representation of the files
const fileTree = this.generateFileTree(files, workspaceRoot);
xmlParts.push(fileTree);
xmlParts.push('</file_map>');
}
// Generate file contents section
xmlParts.push('<file_contents>');
// Add each file with its content
for (const [filePath, { content, tokens }] of files) {
const extension = path.extname(filePath);
let language = extension.substring(1); // Remove the dot
// Handle special cases
// Handle special cases for language detection
if (extension === '.js' || extension === '.jsx') {
language = 'javascript';
} else if (extension === '.ts' || extension === '.tsx') {
language = 'typescript';
} else if (extension === '.md') {
language = 'md';
} else if (extension === '.py') {
language = 'python';
} else if (extension === '.html') {
language = 'html';
} else if (extension === '.css') {
language = 'css';
} else if (extension === '.json') {
language = 'json';
}
xmlParts.push(' <file>');
xmlParts.push(` <path>${path.basename(filePath)}</path>`);
xmlParts.push(` <type>${language}</type>`);
xmlParts.push(` <tokens>${tokens}</tokens>`);
// Use content as is
const formattedContent = content;
// Format content based on settings
let formattedContent = content;
if (settings.includeLineNumbers) {
const lines = content.split('\n');
formattedContent = lines.map((line, i) => `${i + 1}: ${line}`).join('\n');
}
// Get the workspace root path if not already defined
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri?.fsPath || '';
xmlParts.push(` <content><![CDATA[${formattedContent}]]></content>`);
xmlParts.push(' </file>');
}
xmlParts.push(' </files>');
// Add options based on settings
xmlParts.push(' <options>');
if (settings.includeLineNumbers) {
xmlParts.push(' <include_line_numbers>true</include_line_numbers>');
}
if (!settings.includeComments) {
xmlParts.push(' <exclude_comments>true</exclude_comments>');
// Add file entry
xmlParts.push(`File: ${this.getRelativePath(filePath, workspaceRoot)}`);
xmlParts.push(`\`\`\`${language}`);
xmlParts.push(formattedContent);
xmlParts.push('\`\`\`');
}
xmlParts.push('</file_contents>');
// Calculate tokens for toast notification but don't include in XML
if (settings.tokenCalculationEnabled) {
xmlParts.push(` <total_tokens>${Array.from(files.values()).reduce((sum, { tokens }) => sum + tokens, 0)}</total_tokens>`);
const totalTokens = Array.from(files.values()).reduce((sum, { tokens }) => sum + tokens, 0);
// We'll show this in a toast notification but not include it in the XML
vscode.window.showInformationMessage(`Total tokens: ${totalTokens}`);
}
xmlParts.push(' </options>');
xmlParts.push('</prompt>');
return xmlParts.join('\n');
}
/**
* Generate a tree representation of files
* @param files Map of file paths
* @param rootPath The workspace root path
* @returns String representation of the file tree
*/
private static generateFileTree(files: Map<string, any>, rootPath: string): string {
// Create a simple tree representation
const treeLines: string[] = [];
// Group files by directory
const dirMap = new Map<string, string[]>();
for (const filePath of files.keys()) {
const relativePath = this.getRelativePath(filePath, rootPath);
const dir = path.dirname(relativePath);
if (!dirMap.has(dir)) {
dirMap.set(dir, []);
}
dirMap.get(dir)?.push(path.basename(filePath));
}
// Sort directories
const sortedDirs = Array.from(dirMap.keys()).sort();
// Build the tree
for (let i = 0; i < sortedDirs.length; i++) {
const dir = sortedDirs[i];
const isLast = i === sortedDirs.length - 1;
const prefix = isLast ? '└── ' : '├── ';
// Skip root directory
if (dir !== '.') {
treeLines.push(`${prefix}${dir}`);
}
// Add files
const files = dirMap.get(dir)?.sort() || [];
for (let j = 0; j < files.length; j++) {
const file = files[j];
const isLastFile = j === files.length - 1;
const filePrefix = dir === '.' ? (isLastFile ? '└── ' : '├── ') : ' ' + (isLastFile ? '└── ' : '├── ');
treeLines.push(`${filePrefix}${file}`);
}
}
return treeLines.join('\n');
}
/**
* Get the path relative to the workspace root
* @param filePath Absolute file path
* @param rootPath Workspace root path
* @returns Relative path
*/
private static getRelativePath(filePath: string, rootPath: string): string {
if (filePath.startsWith(rootPath)) {
const relativePath = filePath.substring(rootPath.length);
return relativePath.startsWith('/') ? relativePath.substring(1) : relativePath;
}
return filePath;
}
}