UNPKG

semem

Version:

Semantic Memory for Intelligent Agents

943 lines (784 loc) 34.7 kB
/** * Formats content for optimal LLM consumption with structured prompts */ export default class PromptFormatter { constructor(options = {}) { this.config = { defaultFormat: options.defaultFormat || 'structured', includeMetadata: options.includeMetadata !== false, includeInstructions: options.includeInstructions !== false, preserveStructure: options.preserveStructure !== false, contextMarkers: options.contextMarkers !== false, debugMode: options.debugMode || false, ...options }; this.initializeFormats(); this.initializeTemplates(); this.initializeInstructions(); } /** * Initialize available output formats */ initializeFormats() { this.formats = { json: { name: 'JSON Format', handler: this.formatAsJSON.bind(this), description: 'Structured JSON output for programmatic consumption', useCases: ['API responses', 'data processing', 'structured analysis'] }, markdown: { name: 'Markdown Format', handler: this.formatAsMarkdown.bind(this), description: 'Human-readable markdown with structure preservation', useCases: ['documentation', 'reports', 'readable output'] }, structured: { name: 'Structured Prompt Format', handler: this.formatAsStructured.bind(this), description: 'LLM-optimized format with clear sections and context', useCases: ['LLM prompts', 'conversation', 'reasoning tasks'] }, conversational: { name: 'Conversational Format', handler: this.formatAsConversational.bind(this), description: 'Natural language format for chat interfaces', useCases: ['chat responses', 'summaries', 'explanations'] }, analytical: { name: 'Analytical Format', handler: this.formatAsAnalytical.bind(this), description: 'Detailed analysis format with insights and patterns', useCases: ['research', 'analysis', 'insights generation'] } }; } /** * Initialize formatting templates */ initializeTemplates() { this.templates = { structured: { header: '# ZPT Navigation Results\n\n', navigation: '## Navigation Context\n**Zoom:** {zoom}\n**Pan:** {pan}\n**Tilt:** {tilt}\n\n', content: '## Content\n\n{content}\n\n', metadata: '## Metadata\n{metadata}\n\n', footer: '---\n*Generated by ZPT Navigation System*' }, analytical: { header: '# Analysis Report\n\n', summary: '## Executive Summary\n{summary}\n\n', findings: '## Key Findings\n{findings}\n\n', details: '## Detailed Analysis\n{details}\n\n', patterns: '## Patterns & Insights\n{patterns}\n\n', metadata: '## Analysis Metadata\n{metadata}\n\n' }, conversational: { greeting: 'Based on your navigation through the corpus using zoom level "{zoom}", here\'s what I found:\n\n', content: '{content}\n\n', context: 'This analysis was generated using {tilt} representation{filters}.\n\n', closing: 'Would you like to explore further or adjust the navigation parameters?' } }; } /** * Initialize instruction sets for different use cases */ initializeInstructions() { this.instructions = { analysis: { prefix: 'Please analyze the following content extracted from a knowledge corpus:', context: 'The content was selected using specific navigation parameters (zoom/pan/tilt) to focus on relevant information.', guidance: 'Pay attention to patterns, relationships, and key insights. Consider the navigation context when interpreting the results.', suffix: 'Provide a comprehensive analysis considering both the content and the navigation methodology used.' }, summarization: { prefix: 'Please summarize the following corpus content:', context: 'This content represents a focused view of a larger knowledge corpus, filtered by specific criteria.', guidance: 'Create a concise summary that captures the essential information while maintaining context.', suffix: 'Focus on the most important points and their relationships.' }, question_answering: { prefix: 'Use the following corpus content to answer questions:', context: 'The content has been specifically selected and filtered to be relevant to potential queries.', guidance: 'Base your answers strictly on the provided content. If information is not available, indicate this clearly.', suffix: 'Provide accurate, evidence-based responses citing the relevant sections.' }, exploration: { prefix: 'Explore and explain the following content from a knowledge corpus:', context: 'This content represents a specific perspective through the corpus based on navigation parameters.', guidance: 'Identify interesting patterns, connections, and insights. Consider multiple viewpoints.', suffix: 'Highlight discoveries and suggest areas for further exploration.' } }; } /** * Main formatting method - transforms projected content for LLM consumption * @param {Object} projectedContent - Content from TiltProjector * @param {Object} navigationContext - ZPT navigation context * @param {Object} options - Formatting options * @returns {Object} Formatted content ready for LLM */ async format(projectedContent, navigationContext, options = {}) { const startTime = Date.now(); const opts = { ...this.config, ...options }; try { // Determine output format const format = opts.format || this.config.defaultFormat; const formatter = this.formats[format]; if (!formatter) { throw new Error(`Unknown format: ${format}`); } // Prepare formatting context const formattingContext = this.buildFormattingContext( projectedContent, navigationContext, opts ); // Apply format-specific transformation const formattedContent = await formatter.handler(formattingContext, opts); // Add instructions if requested const instructionalContent = this.addInstructions(formattedContent, opts); // Add metadata markers if requested const finalContent = this.addContextMarkers(instructionalContent, formattingContext, opts); const result = { content: finalContent, format, metadata: { originalProjection: projectedContent.representation, outputFormat: format, hasInstructions: opts.includeInstructions, hasMetadata: opts.includeMetadata, processingTime: Date.now() - startTime, tokenEstimate: this.estimateTokenCount(finalContent) }, context: formattingContext }; return result; } catch (error) { throw new Error(`Formatting failed: ${error.message}`); } } /** * Build comprehensive formatting context */ buildFormattingContext(projectedContent, navigationContext, options) { const { representation, data, metadata } = projectedContent; const { zoom, pan, tilt } = navigationContext; return { // Core content projection: { type: representation, data, metadata }, // Navigation context navigation: { zoom, pan, tilt, hasFilters: Object.keys(pan || {}).length > 0, filterSummary: this.summarizeFilters(pan) }, // Content analysis analysis: { contentType: this.analyzeContentType(data), complexity: this.assessComplexity(data), structure: this.analyzeStructure(data), insights: this.extractInsights(data, representation) }, // Formatting context formatting: { timestamp: new Date().toISOString(), options, purpose: options.purpose || 'general' } }; } /** * Format as JSON */ async formatAsJSON(context, options) { const { projection, navigation, analysis } = context; const jsonOutput = { zpt_navigation: { zoom: navigation.zoom, pan: navigation.pan, tilt: navigation.tilt }, content: { type: projection.type, data: projection.data, analysis: options.includeAnalysis ? analysis : undefined }, metadata: options.includeMetadata ? { projection_metadata: projection.metadata, content_analysis: analysis, formatting: context.formatting } : undefined }; // Clean undefined values return JSON.stringify(jsonOutput, (key, value) => value === undefined ? null : value, 2); } /** * Format as Markdown */ async formatAsMarkdown(context, options) { const { projection, navigation, analysis } = context; let markdown = ''; // Header markdown += `# Corpus Navigation Results\n\n`; // Navigation context markdown += `## Navigation Parameters\n\n`; markdown += `- **Zoom Level:** ${navigation.zoom}\n`; markdown += `- **Tilt Representation:** ${navigation.tilt}\n`; if (navigation.hasFilters) { markdown += `- **Applied Filters:** ${navigation.filterSummary}\n`; } markdown += `\n`; // Content section markdown += `## Content\n\n`; markdown += this.formatContentAsMarkdown(projection.data, projection.type); // Analysis section if (options.includeAnalysis && analysis) { markdown += `\n## Analysis\n\n`; markdown += this.formatAnalysisAsMarkdown(analysis); } // Metadata section if (options.includeMetadata) { markdown += `\n## Metadata\n\n`; markdown += this.formatMetadataAsMarkdown(projection.metadata, context.formatting); } return markdown; } /** * Format as structured prompt */ async formatAsStructured(context, options) { const { projection, navigation, analysis } = context; const template = this.templates.structured; let structured = ''; // Header structured += template.header; // Navigation context const panDescription = navigation.hasFilters ? ` with filters: ${navigation.filterSummary}` : ''; structured += template.navigation .replace('{zoom}', navigation.zoom) .replace('{pan}', panDescription) .replace('{tilt}', navigation.tilt); // Content const formattedContent = this.formatContentForLLM(projection.data, projection.type, options); structured += template.content.replace('{content}', formattedContent); // Metadata if (options.includeMetadata) { const metadataText = this.formatMetadataForLLM(projection.metadata, analysis); structured += template.metadata.replace('{metadata}', metadataText); } // Footer structured += template.footer; return structured; } /** * Format as conversational */ async formatAsConversational(context, options) { const { projection, navigation, analysis } = context; const template = this.templates.conversational; let conversational = ''; // Greeting with context conversational += template.greeting.replace('{zoom}', navigation.zoom); // Content in natural language const naturalContent = this.formatContentNaturally(projection.data, projection.type); conversational += template.content.replace('{content}', naturalContent); // Context explanation const filterText = navigation.hasFilters ? ` and filtered by ${navigation.filterSummary}` : ''; conversational += template.context .replace('{tilt}', navigation.tilt) .replace('{filters}', filterText); // Closing conversational += template.closing; return conversational; } /** * Format as analytical */ async formatAsAnalytical(context, options) { const { projection, navigation, analysis } = context; const template = this.templates.analytical; let analytical = ''; // Header analytical += template.header; // Executive summary const summary = this.generateExecutiveSummary(projection.data, navigation, analysis); analytical += template.summary.replace('{summary}', summary); // Key findings const findings = this.extractKeyFindings(projection.data, projection.type, analysis); analytical += template.findings.replace('{findings}', findings); // Detailed analysis const details = this.formatDetailedAnalysis(projection.data, projection.type); analytical += template.details.replace('{details}', details); // Patterns and insights const patterns = this.identifyPatterns(projection.data, analysis); analytical += template.patterns.replace('{patterns}', patterns); // Metadata if (options.includeMetadata) { const metadata = this.formatAnalyticalMetadata(projection.metadata, context.formatting); analytical += template.metadata.replace('{metadata}', metadata); } return analytical; } /** * Content formatting helpers */ formatContentAsMarkdown(data, type) { switch (type) { case 'vector': return this.formatEmbeddingsAsMarkdown(data); case 'text': return this.formatKeywordsAsMarkdown(data); case 'structured': return this.formatGraphAsMarkdown(data); case 'sequence': return this.formatTemporalAsMarkdown(data); default: return `\`\`\`json\n${JSON.stringify(data, null, 2)}\n\`\`\``; } } formatEmbeddingsAsMarkdown(data) { const { embeddings, aggregateStats, centroid } = data; let markdown = `### Embedding Analysis\n\n`; markdown += `- **Total embeddings:** ${embeddings.length}\n`; markdown += `- **Average similarity:** ${aggregateStats.avgSimilarity.toFixed(3)}\n`; markdown += `- **Dimension:** ${aggregateStats.dimension}\n`; markdown += `- **Model:** ${aggregateStats.model}\n\n`; if (embeddings.length > 0) { markdown += `#### Top Similar Items\n\n`; const topItems = embeddings .sort((a, b) => b.similarity - a.similarity) .slice(0, 5); topItems.forEach((item, index) => { markdown += `${index + 1}. **Similarity:** ${item.similarity.toFixed(3)} - ${item.uri}\n`; }); } return markdown; } formatKeywordsAsMarkdown(data) { const { globalKeywords, summary, stats } = data; let markdown = `### Keyword Analysis\n\n`; markdown += `**Summary:** ${summary}\n\n`; markdown += `- **Total unique keywords:** ${stats.totalKeywords}\n`; markdown += `- **Average keywords per item:** ${stats.avgKeywordsPerCorpuscle.toFixed(1)}\n`; markdown += `- **Coverage score:** ${stats.coverageScore.toFixed(3)}\n\n`; if (globalKeywords.length > 0) { markdown += `#### Top Keywords\n\n`; globalKeywords.slice(0, 10).forEach((kw, index) => { markdown += `${index + 1}. **${kw.keyword}** (score: ${kw.score.toFixed(3)}, frequency: ${kw.frequency})\n`; }); } return markdown; } formatGraphAsMarkdown(data) { const { nodes, edges, communities, metrics } = data; let markdown = `### Graph Analysis\n\n`; markdown += `- **Nodes:** ${metrics.nodeCount}\n`; markdown += `- **Edges:** ${metrics.edgeCount}\n`; markdown += `- **Density:** ${metrics.density.toFixed(3)}\n`; markdown += `- **Average degree:** ${metrics.avgDegree.toFixed(1)}\n`; markdown += `- **Communities:** ${communities.length}\n\n`; if (communities.length > 0) { markdown += `#### Communities\n\n`; communities.forEach((community, index) => { markdown += `${index + 1}. **${community.id}** (${community.size} members)\n`; }); } return markdown; } formatTemporalAsMarkdown(data) { const { events, timeline, stats } = data; let markdown = `### Temporal Analysis\n\n`; markdown += `- **Total events:** ${stats.eventCount}\n`; markdown += `- **Timeline span:** ${stats.timelineSpan} periods\n`; markdown += `- **Duration:** ${Math.round(stats.duration / (24 * 60 * 60 * 1000))} days\n`; markdown += `- **Event frequency:** ${stats.frequency.toFixed(2)} events/day\n\n`; if (timeline.length > 0) { markdown += `#### Timeline\n\n`; timeline.slice(0, 10).forEach(period => { markdown += `- **${period.period}**: ${period.count} events (avg score: ${period.avgScore.toFixed(2)})\n`; }); } return markdown; } formatContentForLLM(data, type, options) { switch (type) { case 'vector': return this.formatEmbeddingsForLLM(data); case 'text': return this.formatKeywordsForLLM(data); case 'structured': return this.formatGraphForLLM(data); case 'sequence': return this.formatTemporalForLLM(data); default: return JSON.stringify(data, null, 2); } } formatEmbeddingsForLLM(data) { const { embeddings, aggregateStats } = data; let content = `EMBEDDING ANALYSIS RESULTS:\n\n`; content += `Model: ${aggregateStats.model}\n`; content += `Total items: ${embeddings.length}\n`; content += `Average similarity: ${aggregateStats.avgSimilarity.toFixed(3)}\n\n`; if (embeddings.length > 0) { content += `TOP SIMILAR ITEMS:\n`; embeddings .sort((a, b) => b.similarity - a.similarity) .slice(0, 10) .forEach((item, index) => { content += `${index + 1}. [${item.similarity.toFixed(3)}] ${item.uri}\n`; }); } return content; } formatKeywordsForLLM(data) { const { globalKeywords, summary, corpuscleKeywords } = data; let content = `KEYWORD ANALYSIS RESULTS:\n\n`; content += `Summary: ${summary}\n\n`; content += `KEY TERMS:\n`; globalKeywords.slice(0, 15).forEach((kw, index) => { content += `${index + 1}. ${kw.keyword} (${kw.score.toFixed(3)})\n`; }); if (corpuscleKeywords.length > 0) { content += `\nCONTENT EXCERPTS:\n`; corpuscleKeywords.slice(0, 5).forEach((item, index) => { const topKeywords = item.keywords.slice(0, 3).map(k => k.keyword).join(', '); content += `${index + 1}. Keywords: ${topKeywords}\n Content: ${item.content}\n\n`; }); } return content; } formatGraphForLLM(data) { const { nodes, edges, communities, metrics } = data; let content = `GRAPH ANALYSIS RESULTS:\n\n`; content += `Network structure: ${nodes.length} nodes, ${edges.length} edges\n`; content += `Density: ${metrics.density.toFixed(3)}\n`; content += `Communities: ${communities.length}\n\n`; // Top nodes by score const topNodes = nodes .sort((a, b) => (b.score || 0) - (a.score || 0)) .slice(0, 10); content += `TOP ENTITIES:\n`; topNodes.forEach((node, index) => { content += `${index + 1}. ${node.label} (${node.type}, score: ${(node.score || 0).toFixed(3)})\n`; }); if (communities.length > 0) { content += `\nCOMMUNITIES:\n`; communities.slice(0, 5).forEach((community, index) => { content += `${index + 1}. ${community.id}: ${community.size} members\n`; }); } return content; } formatTemporalForLLM(data) { const { events, timeline, sequences, stats } = data; let content = `TEMPORAL ANALYSIS RESULTS:\n\n`; content += `Time range: ${stats.duration / (24 * 60 * 60 * 1000)} days\n`; content += `Total events: ${events.length}\n`; content += `Event frequency: ${stats.frequency.toFixed(2)} events/day\n\n`; content += `TIMELINE:\n`; timeline.slice(0, 10).forEach(period => { content += `${period.period}: ${period.count} events\n`; }); if (sequences.length > 0) { content += `\nEVENT SEQUENCES:\n`; sequences.slice(0, 3).forEach((seq, index) => { content += `${index + 1}. ${seq.events.length} events over ${Math.round(seq.duration / (24 * 60 * 60 * 1000))} days\n`; }); } return content; } /** * Content naturally formatted for conversation */ formatContentNaturally(data, type) { switch (type) { case 'vector': return this.formatEmbeddingsNaturally(data); case 'text': return this.formatKeywordsNaturally(data); case 'structured': return this.formatGraphNaturally(data); case 'sequence': return this.formatTemporalNaturally(data); default: return 'I found some data, but it\'s in a format I can\'t easily describe.'; } } formatEmbeddingsNaturally(data) { const { embeddings, aggregateStats } = data; let natural = `I analyzed ${embeddings.length} items using semantic embeddings. `; if (aggregateStats.avgSimilarity > 0.7) { natural += `The content shows high semantic similarity (average ${aggregateStats.avgSimilarity.toFixed(2)}), `; natural += `suggesting these items are closely related in meaning.`; } else if (aggregateStats.avgSimilarity > 0.3) { natural += `The content shows moderate semantic relationships, with some related themes emerging.`; } else { natural += `The content is quite diverse, covering different topics and concepts.`; } return natural; } formatKeywordsNaturally(data) { const { globalKeywords, summary } = data; let natural = summary; if (globalKeywords.length > 5) { const topTerms = globalKeywords.slice(0, 5).map(k => k.keyword).join(', '); natural += ` The most prominent terms are: ${topTerms}.`; } return natural; } formatGraphNaturally(data) { const { nodes, communities, metrics } = data; let natural = `I found a network of ${nodes.length} connected entities. `; if (communities.length > 1) { natural += `The network naturally groups into ${communities.length} communities, `; natural += `suggesting distinct but related topic clusters.`; } else { natural += `The entities form a cohesive network with strong interconnections.`; } if (metrics.density > 0.1) { natural += ` The network is well-connected with many relationships between entities.`; } return natural; } formatTemporalNaturally(data) { const { events, stats } = data; let natural = `I analyzed ${events.length} events spanning ${Math.round(stats.duration / (24 * 60 * 60 * 1000))} days. `; if (stats.frequency > 1) { natural += `The activity level is quite high, with about ${stats.frequency.toFixed(1)} events per day.`; } else if (stats.frequency > 0.1) { natural += `The activity is moderate, with events occurring regularly over time.`; } else { natural += `The events are spread out over a longer time period.`; } return natural; } /** * Analysis and insight extraction */ analyzeContentType(data) { if (data.embeddings) return 'semantic_embeddings'; if (data.globalKeywords) return 'keyword_extraction'; if (data.nodes && data.edges) return 'graph_structure'; if (data.events && data.timeline) return 'temporal_sequence'; return 'unknown'; } assessComplexity(data) { let complexity = 0; if (data.embeddings) complexity += data.embeddings.length / 100; if (data.globalKeywords) complexity += data.globalKeywords.length / 50; if (data.nodes) complexity += data.nodes.length / 200; if (data.events) complexity += data.events.length / 500; return Math.min(1.0, complexity); } analyzeStructure(data) { const structure = { hierarchical: false, networked: false, sequential: false, categorical: false }; if (data.nodes && data.edges) structure.networked = true; if (data.events && data.timeline) structure.sequential = true; if (data.communities) structure.hierarchical = true; if (data.globalKeywords) structure.categorical = true; return structure; } extractInsights(data, representation) { const insights = []; switch (representation) { case 'embedding': if (data.aggregateStats?.avgSimilarity > 0.8) { insights.push('High semantic coherence detected'); } break; case 'keywords': if (data.stats?.coverageScore > 0.7) { insights.push('Strong keyword coverage across content'); } break; case 'graph': if (data.metrics?.density > 0.1) { insights.push('Well-connected entity network'); } break; case 'temporal': if (data.patterns?.length > 0) { insights.push('Temporal patterns detected'); } break; } return insights; } /** * Helper methods for specific formatting tasks */ summarizeFilters(pan) { if (!pan || Object.keys(pan).length === 0) return 'none'; const filters = []; if (pan.topic) filters.push(`topic: ${pan.topic.value}`); if (pan.entity) filters.push(`entities: ${pan.entity.count}`); if (pan.temporal) filters.push('temporal constraints'); if (pan.geographic) filters.push('geographic bounds'); return filters.join(', '); } generateExecutiveSummary(data, navigation, analysis) { let summary = `Analysis of corpus content using ${navigation.zoom} zoom level with ${navigation.tilt} representation. `; if (analysis.insights.length > 0) { summary += `Key insights: ${analysis.insights.join(', ')}. `; } summary += `Content complexity: ${(analysis.complexity * 100).toFixed(0)}%.`; return summary; } extractKeyFindings(data, type, analysis) { const findings = []; switch (type) { case 'vector': if (data.aggregateStats) { findings.push(`Semantic similarity: ${data.aggregateStats.avgSimilarity.toFixed(3)}`); findings.push(`Content items analyzed: ${data.embeddings.length}`); } break; case 'text': if (data.stats) { findings.push(`Unique keywords identified: ${data.stats.totalKeywords}`); findings.push(`Keyword coverage: ${(data.stats.coverageScore * 100).toFixed(1)}%`); } break; case 'structured': if (data.metrics) { findings.push(`Network density: ${data.metrics.density.toFixed(3)}`); findings.push(`Communities detected: ${data.communities?.length || 0}`); } break; case 'sequence': if (data.stats) { findings.push(`Event frequency: ${data.stats.frequency.toFixed(2)} events/day`); findings.push(`Temporal sequences: ${data.sequences?.length || 0}`); } break; } return findings.map((finding, index) => `${index + 1}. ${finding}`).join('\n'); } formatDetailedAnalysis(data, type) { // Detailed analysis would go here - simplified for brevity return `Detailed analysis of ${type} data with ${JSON.stringify(data).length} characters of raw data.`; } identifyPatterns(data, analysis) { const patterns = []; if (analysis.structure.networked) { patterns.push('Network connectivity patterns identified'); } if (analysis.structure.sequential) { patterns.push('Temporal progression patterns observed'); } if (analysis.complexity > 0.7) { patterns.push('High complexity suggests rich interconnections'); } return patterns.length > 0 ? patterns.map((p, i) => `${i + 1}. ${p}`).join('\n') : 'No significant patterns detected.'; } /** * Instruction and context enhancement */ addInstructions(content, options) { if (!options.includeInstructions) return content; const instructionSet = options.instructionSet || 'analysis'; const instructions = this.instructions[instructionSet]; if (!instructions) return content; let instructionalContent = `${instructions.prefix}\n\n`; instructionalContent += `${instructions.context}\n\n`; instructionalContent += `${instructions.guidance}\n\n`; instructionalContent += `---\n\n${content}\n\n---\n\n`; instructionalContent += `${instructions.suffix}`; return instructionalContent; } addContextMarkers(content, context, options) { if (!options.contextMarkers) return content; const markers = { start: `<!-- ZPT_START: ${context.navigation.zoom}/${context.navigation.tilt} -->`, end: `<!-- ZPT_END: ${new Date().toISOString()} -->`, metadata: `<!-- ZPT_META: ${JSON.stringify(context.navigation)} -->` }; return `${markers.start}\n${markers.metadata}\n\n${content}\n\n${markers.end}`; } /** * Metadata formatting */ formatMetadataAsMarkdown(metadata, formatting) { let md = '```yaml\n'; md += `timestamp: ${formatting.timestamp}\n`; md += `projection_type: ${metadata.projection?.type || 'unknown'}\n`; md += `processing_time: ${metadata.processingTime || 0}ms\n`; md += '```'; return md; } formatMetadataForLLM(metadata, analysis) { let meta = `Processing Details:\n`; meta += `- Timestamp: ${new Date().toISOString()}\n`; meta += `- Processing time: ${metadata.processingTime || 0}ms\n`; if (analysis) { meta += `- Content complexity: ${(analysis.complexity * 100).toFixed(0)}%\n`; } return meta; } formatAnalyticalMetadata(metadata, formatting) { return this.formatMetadataAsMarkdown(metadata, formatting); } /** * Utility methods */ estimateTokenCount(content) { // Simple token estimation - 4 characters per token average return Math.ceil(content.length / 4); } /** * Get available formats */ getAvailableFormats() { return Object.keys(this.formats); } /** * Get format information */ getFormatInfo(formatName) { return this.formats[formatName] ? { ...this.formats[formatName] } : null; } /** * Get available instruction sets */ getAvailableInstructions() { return Object.keys(this.instructions); } /** * Get instruction set information */ getInstructionInfo(instructionSet) { return this.instructions[instructionSet] ? { ...this.instructions[instructionSet] } : null; } /** * Validate formatting options */ validateOptions(options) { const issues = []; if (options.format && !this.formats[options.format]) { issues.push(`Unknown format: ${options.format}`); } if (options.instructionSet && !this.instructions[options.instructionSet]) { issues.push(`Unknown instruction set: ${options.instructionSet}`); } return { valid: issues.length === 0, issues }; } }