pury
Version:
🛡️ AI-powered security scanner with advanced threat detection, dual reporting system (detailed & summary), and comprehensive code analysis
153 lines • 5.77 kB
JavaScript
import { logger } from '../utils/logger.js';
export class ContextManager {
maxTokensPerRequest;
estimatedTokensPerChar;
constructor(maxTokensPerRequest = 2048) {
this.maxTokensPerRequest = maxTokensPerRequest;
this.estimatedTokensPerChar = 0.25; // Rough estimation: 4 chars ≈ 1 token
}
createAnalysisRequests(files, analysisTypes) {
const requests = [];
for (const file of files) {
const tokenCount = this.estimateTokenCount(file.content);
if (tokenCount > this.maxTokensPerRequest) {
// Split large files into chunks
const chunks = this.splitLargeFile(file);
for (const chunk of chunks) {
requests.push({
code: chunk.content,
filePath: chunk.path,
analysisType: analysisTypes,
context: this.generateFileContext(file)
});
}
}
else {
requests.push({
code: file.content,
filePath: file.path,
analysisType: analysisTypes,
context: this.generateFileContext(file)
});
}
}
return requests;
}
createBatchedRequests(files, analysisTypes) {
const allRequests = this.createAnalysisRequests(files, analysisTypes);
const batches = [];
let currentBatch = [];
let currentBatchTokens = 0;
for (const request of allRequests) {
const requestTokens = this.estimateTokenCount(request.code);
// If adding this request would exceed the batch limit, start a new batch
if (currentBatchTokens + requestTokens > this.maxTokensPerRequest &&
currentBatch.length > 0) {
batches.push(currentBatch);
currentBatch = [request];
currentBatchTokens = requestTokens;
}
else {
currentBatch.push(request);
currentBatchTokens += requestTokens;
}
}
// Add the final batch if it has requests
if (currentBatch.length > 0) {
batches.push(currentBatch);
}
logger.debug(`Created ${batches.length} batches from ${allRequests.length} requests`);
return batches;
}
splitLargeFile(file) {
const chunks = [];
const lines = file.content.split('\n');
const maxLinesPerChunk = Math.floor(this.maxTokensPerRequest / (this.estimatedTokensPerChar * 50)); // Estimate 50 chars per line
for (let i = 0; i < lines.length; i += maxLinesPerChunk) {
const chunkLines = lines.slice(i, i + maxLinesPerChunk);
const chunkContent = chunkLines.join('\n');
chunks.push({
...file,
path: `${file.path}:${i + 1}-${i + chunkLines.length}`,
content: chunkContent,
size: chunkContent.length
});
}
logger.debug(`Split large file ${file.path} into ${chunks.length} chunks`);
return chunks;
}
generateFileContext(file) {
const context = [];
// Add file type information
if (file.extension) {
context.push(`File type: ${file.extension}`);
}
// Add relative path for better understanding
context.push(`Relative path: ${file.relativePath}`);
// Add file size information
context.push(`File size: ${file.size} bytes`);
// Determine likely programming language
const language = this.detectLanguage(file.extension);
if (language) {
context.push(`Language: ${language}`);
}
return context.join(', ');
}
detectLanguage(extension) {
const languageMap = {
'.js': 'JavaScript',
'.jsx': 'JavaScript React',
'.ts': 'TypeScript',
'.tsx': 'TypeScript React',
'.py': 'Python',
'.java': 'Java',
'.c': 'C',
'.cpp': 'C++',
'.cxx': 'C++',
'.cc': 'C++',
'.h': 'C/C++ Header',
'.hpp': 'C++ Header',
'.cs': 'C#',
'.php': 'PHP',
'.rb': 'Ruby',
'.go': 'Go',
'.rs': 'Rust',
'.swift': 'Swift',
'.kt': 'Kotlin',
'.scala': 'Scala',
'.html': 'HTML',
'.css': 'CSS',
'.scss': 'SCSS',
'.sass': 'Sass',
'.json': 'JSON',
'.xml': 'XML',
'.yaml': 'YAML',
'.yml': 'YAML',
'.sql': 'SQL',
'.sh': 'Shell Script',
'.bash': 'Bash Script',
'.ps1': 'PowerShell',
'.bat': 'Batch File',
'.dockerfile': 'Dockerfile'
};
return languageMap[extension.toLowerCase()] || null;
}
estimateTokenCount(text) {
return Math.ceil(text.length * this.estimatedTokensPerChar);
}
optimizePromptLength(prompt, maxLength) {
if (this.estimateTokenCount(prompt) <= maxLength) {
return prompt;
}
// Simple truncation - in production, you might want more sophisticated truncation
const maxChars = Math.floor(maxLength / this.estimatedTokensPerChar);
return `${prompt.substring(0, maxChars)}\n[Content truncated due to length]`;
}
getTokenBudget() {
return {
max: this.maxTokensPerRequest,
estimated: Math.floor(this.maxTokensPerRequest * 0.8) // Leave 20% buffer
};
}
}
//# sourceMappingURL=context-manager.js.map