@claude-vector/core
Version:
Core vector search engine for code intelligence
836 lines (705 loc) • 25.7 kB
JavaScript
/**
* Claude Prompt Optimizer - Claude向け最適化プロンプトテンプレート
*
* 機能:
* - 構造化出力生成(絵文字、構造化マークダウン)
* - コンテキスト情報の階層化
* - 開発タスク別プロンプトテンプレート
* - トークン効率性の最適化
*/
export class ClaudePromptOptimizer {
constructor(options = {}) {
this.options = {
useEmojis: options.useEmojis ?? true,
useStructuredOutput: options.useStructuredOutput ?? true,
maxTokensPerChunk: options.maxTokensPerChunk || 2000,
includeMetrics: options.includeMetrics ?? true,
includeContext: options.includeContext ?? true,
adaptToPhase: options.adaptToPhase ?? true,
...options
};
// プロンプトテンプレート定義
this.templates = {
class_structure: {
emoji: '🏗️',
title: 'CLASS STRUCTURE',
sections: ['overview', 'properties', 'methods', 'inheritance', 'usage'],
priority: 'high'
},
function_implementation: {
emoji: '⚙️',
title: 'FUNCTION',
sections: ['signature', 'purpose', 'parameters', 'implementation', 'examples'],
priority: 'high'
},
module_export: {
emoji: '📦',
title: 'MODULE EXPORT',
sections: ['exports', 'dependencies', 'usage', 'api'],
priority: 'medium'
},
module_import: {
emoji: '📥',
title: 'MODULE IMPORT',
sections: ['source', 'imported_items', 'usage_context'],
priority: 'low'
},
variable_declaration: {
emoji: '📊',
title: 'VARIABLE',
sections: ['type', 'value', 'scope', 'usage'],
priority: 'medium'
},
error_handling: {
emoji: '🚨',
title: 'ERROR HANDLING',
sections: ['error_type', 'cause', 'solution', 'prevention'],
priority: 'critical'
},
test_case: {
emoji: '🧪',
title: 'TEST CASE',
sections: ['test_type', 'scenario', 'expectations', 'implementation'],
priority: 'high'
},
documentation: {
emoji: '📚',
title: 'DOCUMENTATION',
sections: ['description', 'usage', 'examples', 'api_reference'],
priority: 'medium'
},
configuration: {
emoji: '⚙️',
title: 'CONFIGURATION',
sections: ['purpose', 'options', 'defaults', 'examples'],
priority: 'medium'
},
general_code: {
emoji: '💻',
title: 'CODE',
sections: ['overview', 'implementation', 'context'],
priority: 'medium'
}
};
// 開発フェーズ別最適化設定
this.phaseOptimizations = {
exploration: {
emphasize: ['overview', 'purpose', 'architecture', 'relationships'],
includeContext: true,
expandReferences: true,
structuralWeight: 0.4
},
implementation: {
emphasize: ['implementation', 'examples', 'parameters', 'usage'],
includeContext: true,
expandReferences: false,
codeWeight: 0.5
},
debugging: {
emphasize: ['error_type', 'cause', 'solution', 'implementation'],
includeContext: false,
expandReferences: false,
precisionWeight: 0.6
},
refactoring: {
emphasize: ['structure', 'quality', 'patterns', 'improvements'],
includeContext: true,
expandReferences: true,
qualityWeight: 0.4
},
testing: {
emphasize: ['test_type', 'scenario', 'expectations', 'coverage'],
includeContext: true,
expandReferences: false,
testWeight: 0.5
},
documentation: {
emphasize: ['description', 'usage', 'examples', 'api_reference'],
includeContext: true,
expandReferences: true,
clarityWeight: 0.4
}
};
}
/**
* Claude最適化フォーマットの生成
*/
formatForClaude(chunk, searchContext = {}) {
// 安全性チェック:chunkとmetadataの存在確認
if (!chunk || !chunk.metadata) {
console.warn('⚠️ Invalid chunk structure in formatForClaude, using fallback');
return this.createFallbackPrompt(chunk, searchContext);
}
const metadata = chunk.metadata;
const template = this.selectTemplate(metadata);
const phaseOptimization = this.getPhaseOptimization(searchContext.phase);
// トークン効率性の計算
const tokenBudget = this.calculateTokenBudget(chunk, searchContext);
// 構造化プロンプトの生成
const formattedPrompt = this.buildStructuredPrompt(
chunk,
template,
phaseOptimization,
tokenBudget,
searchContext
);
return formattedPrompt;
}
/**
* フォールバック用のプロンプト生成
*/
createFallbackPrompt(chunk, searchContext = {}) {
const content = chunk?.content || 'No content available';
const filename = chunk?.metadata?.file || 'unknown_file';
return {
content: `## 🔍 Code Fragment\n\n**File:** ${filename}\n\n\`\`\`\n${content}\n\`\`\`\n\n*Note: This is a fallback format due to incomplete metadata.*`,
metadata: {
template: 'fallback',
quality: 'basic',
tokens: Math.ceil(content.length / 4),
fallback: true
}
};
}
/**
* テンプレートの選択
*/
selectTemplate(metadata) {
// 安全性チェック:metadataの存在確認
if (!metadata) {
return this.templates.general_code;
}
// AI最適化メタデータからプロンプトテンプレートを取得
if (metadata.aiContext?.promptTemplate) {
return this.templates[metadata.aiContext.promptTemplate] || this.templates.general_code;
}
// セマンティックタイプベースの選択
const semanticType = metadata.semantic?.type || metadata.semanticType;
switch (semanticType) {
case 'class':
return this.templates.class_structure;
case 'function':
return this.templates.function_implementation;
case 'export':
return this.templates.module_export;
case 'import':
return this.templates.module_import;
case 'variable':
return this.templates.variable_declaration;
case 'error':
return this.templates.error_handling;
case 'test':
return this.templates.test_case;
case 'documentation':
return this.templates.documentation;
case 'config':
return this.templates.configuration;
default:
return this.templates.general_code;
}
}
/**
* フェーズ最適化の取得
*/
getPhaseOptimization(phase) {
return this.phaseOptimizations[phase] || this.phaseOptimizations.implementation;
}
/**
* トークン予算の計算
*/
calculateTokenBudget(chunk, searchContext) {
const baseTokens = chunk.metadata.tokens || this.estimateTokens(chunk.content);
const maxTokens = this.options.maxTokensPerChunk;
// 利用可能トークン予算の配分
return {
content: Math.min(baseTokens, maxTokens * 0.7),
metadata: maxTokens * 0.2,
context: maxTokens * 0.1,
total: maxTokens
};
}
/**
* 構造化プロンプトの構築
*/
buildStructuredPrompt(chunk, template, phaseOptimization, tokenBudget, searchContext) {
let prompt = '';
// ヘッダーの生成
prompt += this.buildHeader(chunk, template, searchContext);
// メタデータセクションの生成
if (this.options.includeMetrics) {
prompt += this.buildMetricsSection(chunk, tokenBudget);
}
// コンテキストセクションの生成
if (this.options.includeContext && phaseOptimization.includeContext) {
prompt += this.buildContextSection(chunk, phaseOptimization, searchContext);
}
// メインコンテンツの生成
prompt += this.buildMainContent(chunk, template, phaseOptimization, tokenBudget);
// 開発ノートの生成
prompt += this.buildDevelopmentNotes(chunk, phaseOptimization, searchContext);
// フッターの生成
prompt += this.buildFooter(chunk, searchContext);
return prompt;
}
/**
* ヘッダーの構築
*/
buildHeader(chunk, template, searchContext) {
const metadata = chunk.metadata;
const emoji = this.options.useEmojis ? template.emoji : '';
const title = template.title;
// ファイルパスの相対化
const relativePath = this.getRelativePath(metadata.file, searchContext.projectRoot);
// 行番号の情報
const lineInfo = metadata.startLine && metadata.endLine
? `:${metadata.startLine}${metadata.endLine !== metadata.startLine ? `-${metadata.endLine}` : ''}`
: '';
let header = `\n${emoji} **${title}** | 📍 \`${relativePath}${lineInfo}\`\n`;
// 重要度とメトリクスの追加
if (metadata.aiContext?.importance) {
const importance = Math.round(metadata.aiContext.importance * 100);
header += `⭐ **Importance**: ${importance}% | `;
}
if (metadata.complexity?.cognitive) {
header += `🧠 **Complexity**: ${metadata.complexity.cognitive}/10 | `;
}
if (metadata.semantic?.name && metadata.semantic.name !== 'anonymous') {
header += `🎯 **Name**: \`${metadata.semantic.name}\``;
}
header += '\n';
return header;
}
/**
* メトリクスセクションの構築
*/
buildMetricsSection(chunk, tokenBudget) {
const metadata = chunk.metadata;
let metrics = '\n📊 **Metrics & Quality**:\n';
// 複雑度メトリクス
if (metadata.complexity) {
metrics += `- **Cognitive Complexity**: ${metadata.complexity.cognitive || 'N/A'}\n`;
metrics += `- **Cyclomatic Complexity**: ${metadata.complexity.cyclomatic || 'N/A'}\n`;
if (metadata.complexity.maintainabilityIndex) {
metrics += `- **Maintainability**: ${Math.round(metadata.complexity.maintainabilityIndex)}/100\n`;
}
}
// 品質メトリクス
if (metadata.quality) {
if (metadata.quality.codeQuality) {
metrics += `- **Code Quality**: ${Math.round(metadata.quality.codeQuality * 100)}%\n`;
}
if (metadata.quality.testCoverage) {
metrics += `- **Test Coverage**: ${Math.round(metadata.quality.testCoverage * 100)}%\n`;
}
if (metadata.quality.documentation) {
metrics += `- **Documentation**: ${Math.round(metadata.quality.documentation * 100)}%\n`;
}
}
// AIコンテキスト
if (metadata.aiContext) {
metrics += `- **AI Searchability**: ${Math.round(metadata.aiContext.searchability * 100)}%\n`;
if (metadata.aiContext.tokenEfficiency) {
metrics += `- **Token Efficiency**: ${Math.round(metadata.aiContext.tokenEfficiency * 100)}%\n`;
}
}
return metrics + '\n';
}
/**
* コンテキストセクションの構築
*/
buildContextSection(chunk, phaseOptimization, searchContext) {
const metadata = chunk.metadata;
let context = '🔗 **Context & Relationships**:\n';
// 依存関係
if (metadata.relationships?.dependencies?.length > 0) {
const deps = metadata.relationships.dependencies.slice(0, 5).join(', ');
context += `- **Dependencies**: ${deps}\n`;
}
// 呼び出し関係
if (metadata.relationships?.callGraph?.length > 0) {
const calls = metadata.relationships.callGraph.slice(0, 3).join(', ');
context += `- **Calls**: ${calls}\n`;
}
// セマンティック情報
if (metadata.semantic) {
context += `- **Type**: ${metadata.semantic.type}\n`;
if (metadata.semantic.purpose) {
context += `- **Purpose**: ${metadata.semantic.purpose}\n`;
}
if (metadata.semantic.patterns?.length > 0) {
context += `- **Patterns**: ${metadata.semantic.patterns.join(', ')}\n`;
}
}
// 開発コンテキスト
if (metadata.development) {
context += `- **Stability**: ${Math.round(metadata.development.stability * 100)}%\n`;
if (metadata.development.changeFrequency) {
context += `- **Change Frequency**: ${Math.round(metadata.development.changeFrequency * 100)}%\n`;
}
}
return context + '\n';
}
/**
* メインコンテンツの構築
*/
buildMainContent(chunk, template, phaseOptimization, tokenBudget) {
const metadata = chunk.metadata;
let content = '';
// コンテンツの前処理(トークン制限に基づく)
const processedContent = this.processContentForTokens(chunk.content, tokenBudget.content);
// 言語に基づくシンタックスハイライト
const language = metadata.language || 'text';
// フェーズ最適化に基づく注釈の追加
const annotatedContent = this.addPhaseBasedAnnotations(
processedContent,
metadata,
phaseOptimization
);
content += `\`\`\`${language}\n${annotatedContent}\n\`\`\`\n\n`;
return content;
}
/**
* 開発ノートの構築
*/
buildDevelopmentNotes(chunk, phaseOptimization, searchContext) {
const metadata = chunk.metadata;
let notes = '💡 **Development Notes**:\n';
// フェーズ特有のノート
if (searchContext.phase === 'debugging') {
notes += this.buildDebuggingNotes(metadata);
} else if (searchContext.phase === 'implementation') {
notes += this.buildImplementationNotes(metadata);
} else if (searchContext.phase === 'refactoring') {
notes += this.buildRefactoringNotes(metadata);
} else {
notes += this.buildGeneralNotes(metadata);
}
// コードスメルの警告
if (metadata.quality?.codeSmells?.length > 0) {
notes += `\n⚠️ **Code Smells**: ${metadata.quality.codeSmells.join(', ')}\n`;
}
// ベストプラクティスの提案
if (metadata.quality?.bestPractices?.length > 0) {
notes += `✅ **Best Practices**: ${metadata.quality.bestPractices.join(', ')}\n`;
}
return notes + '\n';
}
/**
* デバッグ用ノート
*/
buildDebuggingNotes(metadata) {
let notes = '';
if (metadata.complexity?.cognitive > 5) {
notes += '- High complexity - potential source of bugs\n';
}
if (metadata.development?.bugHistory?.length > 0) {
const recentBugs = metadata.development.bugHistory.filter(bug => !bug.resolved);
if (recentBugs.length > 0) {
notes += `- Known issues: ${recentBugs.length} unresolved\n`;
}
}
if (metadata.quality?.testCoverage < 0.5) {
notes += '- Low test coverage - consider adding tests\n';
}
return notes;
}
/**
* 実装用ノート
*/
buildImplementationNotes(metadata) {
let notes = '';
if (metadata.relationships?.dependencies?.length > 0) {
notes += `- Required dependencies: ${metadata.relationships.dependencies.slice(0, 3).join(', ')}\n`;
}
if (metadata.semantic?.patterns?.includes('async_pattern')) {
notes += '- Async pattern - handle promises carefully\n';
}
if (metadata.complexity?.maintainabilityIndex < 50) {
notes += '- Consider simplifying for better maintainability\n';
}
return notes;
}
/**
* リファクタリング用ノート
*/
buildRefactoringNotes(metadata) {
let notes = '';
if (metadata.complexity?.cognitive > 10) {
notes += '- High cognitive load - good candidate for refactoring\n';
}
if (metadata.quality?.codeSmells?.includes('long_method')) {
notes += '- Long method - consider breaking into smaller functions\n';
}
if (metadata.development?.changeFrequency > 0.7) {
notes += '- Frequently changed - stability improvements recommended\n';
}
return notes;
}
/**
* 一般的なノート
*/
buildGeneralNotes(metadata) {
let notes = '';
if (metadata.development?.lastModified) {
const lastModified = new Date(metadata.development.lastModified);
const daysAgo = Math.floor((Date.now() - lastModified.getTime()) / (1000 * 60 * 60 * 24));
notes += `- Last modified: ${daysAgo} days ago\n`;
}
if (metadata.aiContext?.importance > 0.8) {
notes += '- High importance component in codebase\n';
}
if (metadata.quality?.documentation > 0.8) {
notes += '- Well documented code\n';
}
return notes;
}
/**
* フッターの構築
*/
buildFooter(chunk, searchContext) {
let footer = '\n---\n';
// 検索スコア情報
if (chunk.score) {
footer += `🎯 **Relevance Score**: ${(chunk.score * 100).toFixed(1)}%`;
}
// AI最適化情報
const metadata = chunk.metadata;
if (metadata.aiContext?.claudeOptimization?.priority) {
footer += ` | 🤖 **AI Priority**: ${Math.round(metadata.aiContext.claudeOptimization.priority * 100)}%`;
}
// タイムスタンプ
if (searchContext.timestamp) {
footer += ` | ⏰ **Retrieved**: ${new Date(searchContext.timestamp).toLocaleTimeString()}`;
}
footer += '\n';
return footer;
}
/**
* コンテンツのトークン制限処理
*/
processContentForTokens(content, maxTokens) {
const estimatedTokens = this.estimateTokens(content);
if (estimatedTokens <= maxTokens) {
return content;
}
// トークン制限を超える場合の処理
const lines = content.split('\n');
const targetLines = Math.floor(lines.length * (maxTokens / estimatedTokens));
const truncatedContent = lines.slice(0, targetLines).join('\n');
if (targetLines < lines.length) {
return truncatedContent + '\n\n// ... (truncated for token limit)';
}
return truncatedContent;
}
/**
* フェーズベース注釈の追加
*/
addPhaseBasedAnnotations(content, metadata, phaseOptimization) {
if (!phaseOptimization.emphasize) {
return content;
}
let annotatedContent = content;
// デバッグフェーズの場合
if (phaseOptimization.emphasize.includes('error_type')) {
annotatedContent = this.addErrorAnnotations(annotatedContent);
}
// 実装フェーズの場合
if (phaseOptimization.emphasize.includes('implementation')) {
annotatedContent = this.addImplementationAnnotations(annotatedContent, metadata);
}
// リファクタリングフェーズの場合
if (phaseOptimization.emphasize.includes('quality')) {
annotatedContent = this.addQualityAnnotations(annotatedContent, metadata);
}
return annotatedContent;
}
/**
* エラー注釈の追加
*/
addErrorAnnotations(content) {
return content
.replace(/(try\s*{)/g, '// Error handling start\n$1')
.replace(/(catch\s*\([^)]*\)\s*{)/g, '// Error caught here\n$1')
.replace(/(throw\s+)/g, '// Error thrown\n$1');
}
/**
* 実装注釈の追加
*/
addImplementationAnnotations(content, metadata) {
let annotated = content;
// 関数の場合
if (metadata.semantic?.type === 'function') {
annotated = annotated.replace(
/(function\s+\w+|const\s+\w+\s*=\s*(?:async\s+)?\([^)]*\)\s*=>)/,
'// Function implementation\n$1'
);
}
// 非同期パターンの場合
if (metadata.semantic?.patterns?.includes('async_pattern')) {
annotated = annotated.replace(/(await\s+)/g, '// Async operation\n$1');
}
return annotated;
}
/**
* 品質注釈の追加
*/
addQualityAnnotations(content, metadata) {
let annotated = content;
// 複雑なロジックの注釈
if (metadata.complexity?.cognitive > 5) {
annotated = '// Complex logic - consider refactoring\n' + annotated;
}
// ベストプラクティスの注釈
if (metadata.quality?.bestPractices?.includes('use_const')) {
annotated = annotated.replace(/(const\s+)/g, '// Good: using const\n$1');
}
return annotated;
}
/**
* 相対パスの取得
*/
getRelativePath(fullPath, projectRoot) {
if (!projectRoot || !fullPath.startsWith(projectRoot)) {
return fullPath;
}
return fullPath.substring(projectRoot.length + 1);
}
/**
* トークン数の推定
*/
estimateTokens(content) {
// 簡略化されたトークン推定
return Math.ceil(content.length / 4);
}
/**
* 複数チャンクの最適化フォーマット
*/
formatMultipleChunks(chunks, searchContext = {}) {
// 安全性チェック:chunksの有効性確認
if (!chunks || chunks.length === 0) {
return '# Search Results\n\nNo valid results found.';
}
let formattedOutput = '';
try {
// 検索サマリーの追加
formattedOutput += this.buildSearchSummary(chunks, searchContext);
} catch (error) {
console.warn('⚠️ Failed to build search summary:', error.message);
formattedOutput += '# Search Results\n\n';
}
// 各チャンクのフォーマット
chunks.forEach((chunk, index) => {
try {
formattedOutput += `\n## Result ${index + 1}\n`;
formattedOutput += this.formatForClaude(chunk, searchContext);
} catch (error) {
console.warn(`⚠️ Failed to format chunk ${index + 1}:`, error.message);
formattedOutput += `\n## Result ${index + 1}\n**Error**: Unable to format this result.\n`;
}
});
// 関連性の分析
if (chunks.length > 1) {
formattedOutput += this.buildRelationshipAnalysis(chunks);
}
return formattedOutput;
}
/**
* 検索サマリーの構築
*/
buildSearchSummary(chunks, searchContext) {
// 安全性チェック:chunksの有効性確認
if (!chunks || chunks.length === 0) {
return '# 🔍 Search Results Summary\n\nNo results found.\n\n';
}
const totalChunks = chunks.length;
const avgScore = chunks.reduce((sum, chunk) => sum + (chunk?.score || 0), 0) / totalChunks;
let summary = `# 🔍 Search Results Summary\n\n`;
summary += `**Query**: "${searchContext?.query || 'N/A'}"\n`;
summary += `**Phase**: ${searchContext?.phase || 'general'}\n`;
summary += `**Results**: ${totalChunks} chunks found\n`;
summary += `**Average Relevance**: ${(avgScore * 100).toFixed(1)}%\n\n`;
// ファイル分布(安全性チェック付き)
const fileDistribution = chunks.reduce((dist, chunk) => {
const file = chunk?.metadata?.file || 'unknown_file';
dist[file] = (dist[file] || 0) + 1;
return dist;
}, {});
summary += `**File Distribution**:\n`;
Object.entries(fileDistribution).forEach(([file, count]) => {
const relativePath = this.getRelativePath(file, searchContext.projectRoot);
summary += `- ${relativePath}: ${count} chunks\n`;
});
return summary + '\n';
}
/**
* 関係性分析の構築
*/
buildRelationshipAnalysis(chunks) {
let analysis = `\n## 🔗 Relationship Analysis\n\n`;
// 共通の依存関係(既存インデックスとの互換性確保)
const allDependencies = chunks.flatMap(chunk => {
const metadata = chunk?.metadata || {};
// 新しい形式と既存形式の両方をサポート
return metadata.relationships?.dependencies || metadata.dependencies || [];
});
const commonDeps = this.findCommonElements(allDependencies);
if (commonDeps.length > 0) {
analysis += `**Common Dependencies**: ${commonDeps.join(', ')}\n`;
}
// 複雑度分布(既存インデックスとの互換性確保)
const complexities = chunks
.map(chunk => chunk?.metadata?.complexity?.cognitive)
.filter(c => c !== undefined);
if (complexities.length > 0) {
const avgComplexity = complexities.reduce((sum, c) => sum + c, 0) / complexities.length;
analysis += `**Average Complexity**: ${avgComplexity.toFixed(1)}/10\n`;
}
// セマンティックタイプ分布(既存インデックスとの互換性確保)
const typeDistribution = chunks.reduce((dist, chunk) => {
const metadata = chunk?.metadata || {};
// 新しい形式と既存形式の両方をサポート
const type = metadata.semantic?.type || metadata.semanticType || 'unknown';
dist[type] = (dist[type] || 0) + 1;
return dist;
}, {});
analysis += `**Type Distribution**: ${Object.entries(typeDistribution)
.map(([type, count]) => `${type}(${count})`)
.join(', ')}\n`;
return analysis;
}
/**
* 共通要素の検出
*/
findCommonElements(array) {
const counts = array.reduce((acc, item) => {
acc[item] = (acc[item] || 0) + 1;
return acc;
}, {});
return Object.entries(counts)
.filter(([, count]) => count > 1)
.map(([item]) => item);
}
/**
* 設定の更新
*/
updateOptions(newOptions) {
this.options = { ...this.options, ...newOptions };
}
/**
* テンプレートの追加
*/
addTemplate(name, template) {
this.templates[name] = template;
}
/**
* 統計情報の取得
*/
getStats() {
return {
templatesCount: Object.keys(this.templates).length,
phaseOptimizations: Object.keys(this.phaseOptimizations).length,
options: this.options,
version: '1.0.0'
};
}
}