UNPKG

abyss-ai

Version:

Autonomous AI coding agent - enhanced OpenCode with autonomous capabilities

790 lines (649 loc) 22.4 kB
import { ReasoningMode, type ProcessingContext, type ProcessingResult } from "../types/agent" import { BaseReasoningProcessor } from "./reasoning-processor" // Ultrareasoning - Structural/Logical Validation export class UltrareasoningProcessor extends BaseReasoningProcessor { readonly mode = ReasoningMode.ULTRAREASONING async process(code: string, context: ProcessingContext): Promise<ProcessingResult> { this.log.info("Starting ultrareasoning analysis", { codeLength: code.length, language: context.language }) const { result: analysisResult, duration } = await this.measureExecutionTime(async () => { // Deep structural and logical validation const structureValidation = await this.validateStructure(code) const logicalValidation = await this.validateLogic(code, context) const consistencyCheck = await this.checkConsistency(code, context) return { structure: structureValidation, logic: logicalValidation, consistency: consistencyCheck } }) const confidence = this.calculateConfidence(analysisResult) const validationReport = this.generateValidationReport( analysisResult.structure, analysisResult.logic ) return { type: 'ultrareasoning', result: analysisResult, confidence, processingTime: duration, validationReport } } calculateConfidence(result: any): number { if (!result) return 0.1 const { structure, logic, consistency } = result // Weight the confidence based on validation success const structureScore = (structure.score || 0) * 0.4 const logicScore = (logic.score || 0) * 0.4 const consistencyScore = (consistency.score || 0) * 0.2 return Math.min(1, structureScore + logicScore + consistencyScore) } private async validateStructure(code: string) { this.log.debug("Validating code structure") const structure = this.analyzeCodeStructure(code) const issues = [] let score = 1.0 // Syntax validation const syntaxIssues = this.checkSyntax(code) if (syntaxIssues.length > 0) { issues.push(...syntaxIssues) score -= syntaxIssues.length * 0.1 } // Structural patterns const structuralIssues = this.checkStructuralPatterns(code, structure) if (structuralIssues.length > 0) { issues.push(...structuralIssues) score -= structuralIssues.length * 0.05 } // Architectural validation const architecturalIssues = this.validateArchitecture(structure) if (architecturalIssues.length > 0) { issues.push(...architecturalIssues) score -= architecturalIssues.length * 0.1 } return { score: Math.max(0, score), issues, structure, metrics: this.calculateStructuralMetrics(structure), valid: issues.length === 0 } } private checkSyntax(code: string) { const issues = [] // Basic syntax checks const braceBalance = this.checkBraceBalance(code) if (!braceBalance.balanced) { issues.push({ type: 'syntax', severity: 'high', message: `Unbalanced braces: ${braceBalance.issue}`, line: braceBalance.line }) } const parenBalance = this.checkParenthesesBalance(code) if (!parenBalance.balanced) { issues.push({ type: 'syntax', severity: 'high', message: `Unbalanced parentheses: ${parenBalance.issue}`, line: parenBalance.line }) } // Common syntax errors const commonErrors = this.checkCommonSyntaxErrors(code) issues.push(...commonErrors) return issues } private checkBraceBalance(code: string) { let balance = 0 let line = 1 let lastImbalanceLine = 0 for (let i = 0; i < code.length; i++) { if (code[i] === '\n') line++ if (code[i] === '{') { balance++ } else if (code[i] === '}') { balance-- if (balance < 0) { lastImbalanceLine = line } } } return { balanced: balance === 0, issue: balance > 0 ? 'Missing closing braces' : 'Extra closing braces', line: lastImbalanceLine || line } } private checkParenthesesBalance(code: string) { let balance = 0 let line = 1 let lastImbalanceLine = 0 for (let i = 0; i < code.length; i++) { if (code[i] === '\n') line++ if (code[i] === '(') { balance++ } else if (code[i] === ')') { balance-- if (balance < 0) { lastImbalanceLine = line } } } return { balanced: balance === 0, issue: balance > 0 ? 'Missing closing parentheses' : 'Extra closing parentheses', line: lastImbalanceLine || line } } private checkCommonSyntaxErrors(code: string) { const issues: any[] = [] const lines = code.split('\n') lines.forEach((line, index) => { const lineNum = index + 1 // Missing semicolons (for languages that use them) if (line.match(/^[^\/]*[a-zA-Z0-9_\]]$/) && !line.trim().endsWith(';') && !line.includes('{')) { issues.push({ type: 'syntax', severity: 'low', message: 'Possible missing semicolon', line: lineNum }) } // Unclosed strings const quotes = line.match(/["'`]/g) if (quotes && quotes.length % 2 !== 0) { issues.push({ type: 'syntax', severity: 'medium', message: 'Possible unclosed string', line: lineNum }) } }) return issues } private checkStructuralPatterns(code: string, structure: any) { const issues: any[] = [] // Function complexity if (structure.functions) { structure.functions.forEach((funcName: string) => { const funcComplexity = this.getFunctionComplexity(code, funcName) if (funcComplexity > 10) { issues.push({ type: 'structural', severity: 'medium', message: `Function '${funcName}' has high cyclomatic complexity (${funcComplexity})`, suggestion: 'Consider breaking down into smaller functions' }) } }) } // Deep nesting const maxNesting = this.getMaxNestingDepth(code) if (maxNesting > 4) { issues.push({ type: 'structural', severity: 'medium', message: `Deep nesting detected (${maxNesting} levels)`, suggestion: 'Consider reducing nesting depth' }) } // Long parameter lists const longParams = this.findLongParameterLists(code) longParams.forEach(func => { issues.push({ type: 'structural', severity: 'low', message: `Function has many parameters (${func.paramCount})`, suggestion: 'Consider using an options object' }) }) return issues } private getFunctionComplexity(code: string, funcName: string): number { const funcRegex = new RegExp(`function\\s+${funcName}[^{]*{([^}]*)}`, 's') const match = code.match(funcRegex) if (match) { return this.calculateUltraCyclomaticComplexity(match[1]) } return 0 } private calculateUltraCyclomaticComplexity(code: string): number { const patterns = [ /\bif\s*\(/g, /\belse\s+if\b/g, /\bwhile\s*\(/g, /\bfor\s*\(/g, /\bcase\s+/g, /\bcatch\s*\(/g, /\?\s*.*\s*:/g, /&&/g, /\|\|/g ] return patterns.reduce((complexity, pattern) => { const matches = code.match(pattern) return complexity + (matches ? matches.length : 0) }, 1) } private getMaxNestingDepth(code: string): number { let maxDepth = 0 let currentDepth = 0 for (const char of code) { if (char === '{') { currentDepth++ maxDepth = Math.max(maxDepth, currentDepth) } else if (char === '}') { currentDepth-- } } return maxDepth } private findLongParameterLists(code: string) { const funcRegex = /function\s+(\w+)\s*\(([^)]*)\)/g const longParams = [] let match while ((match = funcRegex.exec(code)) !== null) { const params = match[2].split(',').filter(p => p.trim()) if (params.length > 5) { longParams.push({ name: match[1], paramCount: params.length }) } } return longParams } private validateArchitecture(structure: any) { const issues: any[] = [] // Check for circular dependencies if (structure.imports && structure.imports.length > 0) { const circularDeps = this.detectCircularDependencies(structure.imports) if (circularDeps.length > 0) { issues.push({ type: 'architectural', severity: 'high', message: 'Potential circular dependencies detected', dependencies: circularDeps }) } } // Check separation of concerns const concernsIssues = this.checkSeparationOfConcerns(structure) issues.push(...concernsIssues) return issues } private detectCircularDependencies(imports: string[]): string[] { // Simplified circular dependency detection const relativePaths = imports.filter(imp => imp.startsWith('.')) const duplicates = relativePaths.filter((item, index) => relativePaths.indexOf(item) !== index) return duplicates } private checkSeparationOfConcerns(structure: any) { const issues: any[] = [] // Check if a single file has too many responsibilities const responsibilities = [] if (structure.functions && structure.functions.length > 10) { responsibilities.push('many functions') } if (structure.classes && structure.classes.length > 3) { responsibilities.push('multiple classes') } if (structure.imports && structure.imports.length > 15) { responsibilities.push('many dependencies') } if (responsibilities.length > 2) { issues.push({ type: 'architectural', severity: 'medium', message: 'File may have too many responsibilities', responsibilities, suggestion: 'Consider splitting into multiple files' }) } return issues } private calculateStructuralMetrics(structure: any) { return { linesOfCode: structure.lineCount, cyclomaticComplexity: structure.complexity, functionCount: structure.functions?.length || 0, classCount: structure.classes?.length || 0, importCount: structure.imports?.length || 0, cohesion: this.calculateCohesion(structure), coupling: this.calculateCoupling(structure) } } private calculateCohesion(structure: any): number { // Simplified cohesion calculation const totalElements = (structure.functions?.length || 0) + (structure.classes?.length || 0) const imports = structure.imports?.length || 0 if (totalElements === 0) return 1 // Higher cohesion when fewer external dependencies relative to internal elements return Math.max(0, 1 - (imports / (totalElements * 2))) } private calculateCoupling(structure: any): number { // Simplified coupling calculation based on imports const imports = structure.imports?.length || 0 // Normalize coupling score (lower is better) return Math.min(1, imports / 10) } private async validateLogic(code: string, _context: ProcessingContext) { this.log.debug("Validating code logic") const issues = [] let score = 1.0 // Data flow analysis const dataFlowIssues = this.analyzeDataFlow(code) if (dataFlowIssues.length > 0) { issues.push(...dataFlowIssues) score -= dataFlowIssues.length * 0.1 } // Logical consistency checks const consistencyIssues = this.checkLogicalConsistency(code) if (consistencyIssues.length > 0) { issues.push(...consistencyIssues) score -= consistencyIssues.length * 0.15 } // Type consistency (if applicable) const typeIssues = this.checkTypeConsistency(code) if (typeIssues.length > 0) { issues.push(...typeIssues) score -= typeIssues.length * 0.1 } return { score: Math.max(0, score), issues, dataFlow: this.mapDataFlow(code), valid: issues.filter(i => i.severity === 'high').length === 0 } } private analyzeDataFlow(code: string) { const issues: any[] = [] // Check for undefined variables const undefinedVars = this.findUndefinedVariables(code) undefinedVars.forEach(varName => { issues.push({ type: 'logic', severity: 'high', message: `Variable '${varName}' may be used before definition`, variable: varName }) }) // Check for unused variables const unusedVars = this.findUnusedVariables(code) unusedVars.forEach(varName => { issues.push({ type: 'logic', severity: 'low', message: `Variable '${varName}' is declared but never used`, variable: varName }) }) return issues } private findUndefinedVariables(code: string): string[] { // Simplified undefined variable detection const declared = new Set<string>() const used = new Set<string>() // Find declarations const declMatches = code.matchAll(/(?:let|const|var)\s+(\w+)/g) for (const match of declMatches) { declared.add(match[1]) } // Find usage const useMatches = code.matchAll(/\b(\w+)\s*[=\(\[\.]/g) for (const match of useMatches) { used.add(match[1]) } // Return variables used but not declared return Array.from(used).filter(v => !declared.has(v) && !this.isBuiltIn(v)) } private findUnusedVariables(code: string): string[] { const declared = new Set<string>() const used = new Set<string>() // Find declarations const declMatches = code.matchAll(/(?:let|const|var)\s+(\w+)/g) for (const match of declMatches) { declared.add(match[1]) } // Find usage (excluding declarations) const useMatches = code.matchAll(/(?<!(?:let|const|var)\s+)\b(\w+)\b/g) for (const match of useMatches) { used.add(match[1]) } // Return declared but unused variables return Array.from(declared).filter(v => !used.has(v)) } private isBuiltIn(varName: string): boolean { const builtIns = [ 'console', 'window', 'document', 'process', 'global', 'require', 'module', 'exports', 'Buffer', 'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval', 'Promise' ] return builtIns.includes(varName) } private checkLogicalConsistency(code: string) { const issues: any[] = [] // Check for logical contradictions const contradictions = this.findLogicalContradictions(code) issues.push(...contradictions) // Check for unreachable code const unreachable = this.findUnreachableCode(code) issues.push(...unreachable) return issues } private findLogicalContradictions(code: string) { const issues: any[] = [] const lines = code.split('\n') lines.forEach((line, index) => { // Check for always true/false conditions if (line.includes('if (true)') || line.includes('if(true)')) { issues.push({ type: 'logic', severity: 'medium', message: 'Condition is always true', line: index + 1 }) } if (line.includes('if (false)') || line.includes('if(false)')) { issues.push({ type: 'logic', severity: 'medium', message: 'Condition is always false', line: index + 1 }) } }) return issues } private findUnreachableCode(code: string) { const issues: any[] = [] const lines = code.split('\n') for (let i = 0; i < lines.length - 1; i++) { const line = lines[i].trim() const nextLine = lines[i + 1].trim() // Code after return statement if (line.includes('return') && nextLine && !nextLine.startsWith('}') && !nextLine.startsWith('//')) { issues.push({ type: 'logic', severity: 'medium', message: 'Unreachable code after return statement', line: i + 2 }) } } return issues } private checkTypeConsistency(code: string) { const issues = [] // Basic type consistency checks const typeIssues = this.findTypeInconsistencies(code) issues.push(...typeIssues) return issues } private findTypeInconsistencies(code: string) { const issues = [] // Check for number/string comparisons const numStringComparisons = code.match(/\d+\s*[=!]==\s*["'`]|["'`]\s*[=!]==\s*\d+/g) if (numStringComparisons) { issues.push({ type: 'type', severity: 'medium', message: 'Comparing number with string', suggestion: 'Consider using strict equality (===) and type conversion' }) } return issues } private mapDataFlow(code: string) { // Simplified data flow mapping const variables = [] const functions = [] // Extract variable assignments const assignments = code.matchAll(/(\w+)\s*=\s*([^;]+)/g) for (const match of assignments) { variables.push({ name: match[1], assignment: match[2].trim() }) } // Extract function calls const calls = code.matchAll(/(\w+)\s*\(/g) for (const match of calls) { functions.push(match[1]) } return { variables, functions } } private async checkConsistency(code: string, _context: ProcessingContext) { this.log.debug("Checking code consistency") const issues = [] let score = 1.0 // Naming consistency const namingIssues = this.checkNamingConsistency(code) if (namingIssues.length > 0) { issues.push(...namingIssues) score -= namingIssues.length * 0.05 } // Style consistency const styleIssues = this.checkStyleConsistency(code) if (styleIssues.length > 0) { issues.push(...styleIssues) score -= styleIssues.length * 0.02 } // Pattern consistency const patternIssues = this.checkPatternConsistency(code) if (patternIssues.length > 0) { issues.push(...patternIssues) score -= patternIssues.length * 0.1 } return { score: Math.max(0, score), issues, valid: issues.filter(i => i.severity === 'high').length === 0 } } private checkNamingConsistency(code: string) { const issues = [] // Check variable naming conventions const variables = code.match(/(?:let|const|var)\s+(\w+)/g) || [] const namingStyles = new Set() variables.forEach(varDecl => { const varName = varDecl.split(/\s+/)[1] if (varName.includes('_')) { namingStyles.add('snake_case') } else if (varName.match(/[a-z][A-Z]/)) { namingStyles.add('camelCase') } else if (varName.match(/^[A-Z]/)) { namingStyles.add('PascalCase') } }) if (namingStyles.size > 1) { issues.push({ type: 'consistency', severity: 'low', message: 'Inconsistent variable naming conventions', styles: Array.from(namingStyles) }) } return issues } private checkStyleConsistency(code: string) { const issues = [] // Check indentation consistency const lines = code.split('\n').filter(line => line.trim()) const indentations = new Set() lines.forEach(line => { const indent = line.match(/^(\s*)/)?.[1] || '' if (indent.length > 0) { indentations.add(indent.includes('\t') ? 'tabs' : `${indent.length}spaces`) } }) if (indentations.size > 2) { // Allow some variation issues.push({ type: 'consistency', severity: 'low', message: 'Inconsistent indentation style', styles: Array.from(indentations) }) } return issues } private checkPatternConsistency(code: string) { const issues = [] // Check error handling patterns const hasAsyncAwait = code.includes('async') && code.includes('await') const hasPromises = code.includes('Promise') || code.includes('.then(') const hasTryCatch = code.includes('try') && code.includes('catch') if (hasAsyncAwait && hasPromises && !hasTryCatch) { issues.push({ type: 'consistency', severity: 'medium', message: 'Mixed async patterns without proper error handling', suggestion: 'Consider consistent error handling with try-catch blocks' }) } return issues } private generateValidationReport(structureValidation: any, logicalValidation: any) { const totalIssues = [ ...(structureValidation.issues || []), ...(logicalValidation.issues || []) ] const severityCounts = { high: totalIssues.filter(i => i.severity === 'high').length, medium: totalIssues.filter(i => i.severity === 'medium').length, low: totalIssues.filter(i => i.severity === 'low').length } return { summary: { totalIssues: totalIssues.length, severityCounts, structureScore: structureValidation.score, logicScore: logicalValidation.score, overallScore: (structureValidation.score + logicalValidation.score) / 2 }, recommendations: this.generateRecommendations(totalIssues), metrics: structureValidation.metrics } } private generateRecommendations(issues: any[]) { const recommendations = [] const highIssues = issues.filter(i => i.severity === 'high') if (highIssues.length > 0) { recommendations.push('Address high-severity issues immediately') } const structuralIssues = issues.filter(i => i.type === 'structural') if (structuralIssues.length > 3) { recommendations.push('Consider refactoring for better code structure') } const logicIssues = issues.filter(i => i.type === 'logic') if (logicIssues.length > 0) { recommendations.push('Review logic flow and data handling') } return recommendations } }