UNPKG

ai-debug-local-mcp

Version:

🎯 ENHANCED AI GUIDANCE v4.1.2: Dramatically improved tool descriptions help AI users choose the right tools instead of 'close enough' options. Ultra-fast keyboard automation (10x speed), universal recording, multi-ecosystem debugging support, and compreh

489 lines 20.6 kB
/** * Verification-First Orchestrator - Always verifies before trusting */ export class VerificationFirstOrchestrator { name = 'verification_first_orchestrator'; description = `TRUST BUT VERIFY MODE. Always gathers evidence before accepting claims.`; toolExecutor; // Will be injected by UniversalRealHandler // Core verification tools that provide ground truth VERIFICATION_SUITE = { visual: ['take_screenshot', 'capture_full_page', 'visual_diff'], console: ['get_console_logs', 'get_console_errors', 'get_console_warnings'], dom: ['get_dom_snapshot', 'check_element_exists', 'get_element_state'], network: ['get_network_requests', 'get_failed_requests', 'get_api_responses'], performance: ['get_performance_metrics', 'get_memory_usage', 'get_cpu_usage'], state: ['get_application_state', 'get_local_storage', 'get_session_storage'] }; async orchestrate(task) { const startTime = Date.now(); const taskDescription = task.description || task.task || ''; try { // Step 0: Initialize debugging session if URL is provided let sessionId; if (task.url && this.toolExecutor) { const sessionResult = await this.toolExecutor.execute('inject_debugging', { url: task.url }, {}); if (sessionResult.success) { sessionId = sessionResult.sessionId; console.error(`🔍 Debugging session initialized: ${sessionId}`); } } // Step 1: Gather baseline evidence FIRST const evidence = await this.gatherEvidence({ ...task, sessionId }); // Step 2: Analyze evidence to understand actual state const actualState = this.analyzeEvidence(evidence); // Step 3: Now delegate to sub-agents with evidence context const subAgentResults = await this.delegateWithEvidence(taskDescription, actualState, evidence); // Step 4: Verify sub-agent claims against evidence const verification = this.verifyClaimsAgainstEvidence(subAgentResults, evidence, actualState); // Step 5: Generate findings based on verification const findings = this.generateFindings(verification, actualState); return { success: true, summary: this.generateEvidenceBasedSummary(verification), findings: { critical: findings.filter(f => f.severity === 'critical'), warnings: findings.filter(f => f.severity === 'warning'), info: findings.filter(f => f.severity === 'info') }, suggestions: this.generateSuggestions(verification, actualState), nextSteps: this.generateVerifiedRecommendations(verification, actualState), metadata: { duration: Date.now() - startTime, agentsUsed: [subAgentResults.agent || 'debug_agent'], confidence: verification.confidenceScore, evidencePoints: Object.keys(evidence).length, verificationsPerformed: verification.checksPerformed, discrepanciesFound: verification.discrepancies.length } }; } catch (error) { return { success: false, summary: `Verification-first orchestration failed: ${error instanceof Error ? error.message : String(error)}`, metadata: { duration: Date.now() - startTime, agentsUsed: [], confidence: 0 } }; } } async gatherEvidence(task) { const evidence = {}; const evidenceNeeded = this.determineEvidenceNeeded(task); // Gather evidence in parallel for speed const gatheringTasks = []; if (evidenceNeeded.visual) { gatheringTasks.push(this.gatherVisualEvidence(task.sessionId).then(data => { evidence.visual = data; })); } if (evidenceNeeded.console) { gatheringTasks.push(this.gatherConsoleEvidence(task.sessionId).then(data => { evidence.console = data; })); } if (evidenceNeeded.dom) { gatheringTasks.push(this.gatherDOMEvidence(task.sessionId).then(data => { evidence.dom = data; })); } if (evidenceNeeded.network) { gatheringTasks.push(this.gatherNetworkEvidence(task.sessionId).then(data => { evidence.network = data; })); } if (evidenceNeeded.performance) { gatheringTasks.push(this.gatherPerformanceEvidence(task.sessionId).then(data => { evidence.performance = data; })); } await Promise.all(gatheringTasks); return evidence; } determineEvidenceNeeded(task) { const taskStr = JSON.stringify(task).toLowerCase(); return { visual: true, // Always capture visual state console: taskStr.includes('error') || taskStr.includes('console'), dom: taskStr.includes('element') || taskStr.includes('component'), network: taskStr.includes('api') || taskStr.includes('request'), performance: taskStr.includes('slow') || taskStr.includes('performance') }; } async gatherVisualEvidence(sessionId) { try { const params = sessionId ? { sessionId } : {}; const screenshot = await this.executeTool('take_screenshot', params); const pageTitle = await this.executeTool('get_page_title', params); const currentUrl = await this.executeTool('get_current_url', params); return { screenshot, pageTitle, currentUrl, timestamp: new Date() }; } catch (error) { return { error: error instanceof Error ? error.message : String(error) }; } } async gatherConsoleEvidence(sessionId) { try { const params = sessionId ? { sessionId } : {}; const logs = await this.executeTool('get_console_logs', params); const errors = await this.executeTool('get_console_errors', params); const warnings = await this.executeTool('get_console_warnings', params); return { totalLogs: logs?.length || 0, errors: errors || [], warnings: warnings || [], hasErrors: (errors?.length || 0) > 0 }; } catch (error) { return { error: error instanceof Error ? error.message : String(error) }; } } async gatherDOMEvidence(sessionId) { try { const params = sessionId ? { sessionId } : {}; const snapshot = await this.executeTool('get_dom_snapshot', params); return { snapshot, elementCount: this.countElements(snapshot), timestamp: new Date() }; } catch (error) { return { error: error instanceof Error ? error.message : String(error) }; } } async gatherNetworkEvidence(sessionId) { try { const params = sessionId ? { sessionId } : {}; const requests = await this.executeTool('get_network_requests', params); const failed = requests?.filter((r) => r.status >= 400) || []; return { totalRequests: requests?.length || 0, failedRequests: failed, hasFailures: failed.length > 0 }; } catch (error) { return { error: error instanceof Error ? error.message : String(error) }; } } async gatherPerformanceEvidence(sessionId) { try { const params = sessionId ? { sessionId } : {}; const metrics = await this.executeTool('get_performance_metrics', params); return { metrics, isSlowLoad: (metrics?.loadTime || 0) > 3000 }; } catch (error) { return { error: error instanceof Error ? error.message : String(error) }; } } analyzeEvidence(evidence) { return { hasVisualContent: !evidence.visual?.error && evidence.visual?.screenshot, hasConsoleErrors: evidence.console?.hasErrors || false, errorCount: evidence.console?.errors?.length || 0, hasNetworkFailures: evidence.network?.hasFailures || false, failedRequestCount: evidence.network?.failedRequests?.length || 0, isPerformanceIssue: evidence.performance?.isSlowLoad || false, pageLoaded: evidence.visual?.pageTitle && evidence.visual?.currentUrl, summary: this.generateStateSummary(evidence) }; } generateStateSummary(evidence) { const issues = []; if (evidence.console?.hasErrors) { issues.push(`${evidence.console.errors.length} console errors`); } if (evidence.network?.hasFailures) { issues.push(`${evidence.network.failedRequests.length} failed network requests`); } if (evidence.performance?.isSlowLoad) { issues.push('slow page load detected'); } if (issues.length === 0) { return 'No obvious issues detected in evidence'; } return `Found: ${issues.join(', ')}`; } async delegateWithEvidence(task, actualState, evidence) { const enhancedTask = { description: task, evidenceContext: { actualState, knownIssues: this.extractKnownIssues(actualState), evidence: this.sanitizeEvidence(evidence) } }; const subAgent = this.selectSubAgent(task, actualState); return await this.callSubAgent(subAgent, enhancedTask); } extractKnownIssues(state) { const issues = []; if (state.hasConsoleErrors) { issues.push(`Console has ${state.errorCount} errors`); } if (state.hasNetworkFailures) { issues.push(`${state.failedRequestCount} network requests failed`); } if (state.isPerformanceIssue) { issues.push('Performance issues detected'); } return issues; } sanitizeEvidence(evidence) { return { visual: { hasScreenshot: !!evidence.visual?.screenshot }, console: evidence.console, network: { totalRequests: evidence.network?.totalRequests, failedCount: evidence.network?.failedRequests?.length }, performance: evidence.performance }; } verifyClaimsAgainstEvidence(subAgentResults, evidence, actualState) { const discrepancies = []; const checks = []; const claims = this.extractClaims(subAgentResults); for (const claim of claims) { const check = this.verifyClaim(claim, evidence, actualState); checks.push(check); if (!check.verified) { discrepancies.push({ claim: claim.statement, evidence: check.evidence, reason: check.reason }); } } const verifiedChecks = checks.filter(c => c.verified).length; const confidenceScore = checks.length > 0 ? verifiedChecks / checks.length : 0.5; return { results: checks, discrepancies, checksPerformed: checks.length, confidenceScore, confidenceBreakdown: this.calculateConfidenceBreakdown(checks), confidenceReasoning: this.explainConfidence(confidenceScore, discrepancies) }; } extractClaims(subAgentResults) { const claims = []; if (subAgentResults.summary?.includes('no issues')) { claims.push({ statement: 'No issues found', type: 'no_issues' }); } if (subAgentResults.summary?.includes('working correctly')) { claims.push({ statement: 'System working correctly', type: 'working' }); } if (subAgentResults.findings?.errors === 0) { claims.push({ statement: 'No errors detected', type: 'no_errors' }); } return claims; } verifyClaim(claim, evidence, state) { switch (claim.type) { case 'no_issues': return { claim: claim.statement, verified: !state.hasConsoleErrors && !state.hasNetworkFailures, evidence: state.summary, reason: state.hasConsoleErrors || state.hasNetworkFailures ? 'Evidence shows issues exist' : 'Evidence confirms no issues' }; case 'no_errors': return { claim: claim.statement, verified: state.errorCount === 0, evidence: `Found ${state.errorCount} errors in console`, reason: state.errorCount > 0 ? 'Console errors detected' : 'No errors found' }; case 'working': return { claim: claim.statement, verified: state.pageLoaded && !state.hasConsoleErrors && !state.hasNetworkFailures, evidence: state.summary, reason: this.explainWorkingStatus(state) }; default: return { claim: claim.statement, verified: false, evidence: 'Unable to verify', reason: 'Unknown claim type' }; } } explainWorkingStatus(state) { if (!state.pageLoaded) return 'Page did not load properly'; if (state.hasConsoleErrors) return 'Console errors indicate problems'; if (state.hasNetworkFailures) return 'Network failures detected'; if (state.isPerformanceIssue) return 'Performance issues present'; return 'Evidence supports working state'; } calculateConfidenceBreakdown(checks) { return { totalClaims: checks.length, verified: checks.filter(c => c.verified).length, unverified: checks.filter(c => !c.verified).length, byType: this.groupChecksByType(checks) }; } groupChecksByType(checks) { const grouped = {}; checks.forEach(check => { const type = check.claim.split(' ')[0]; if (!grouped[type]) { grouped[type] = { verified: 0, total: 0 }; } grouped[type].total++; if (check.verified) grouped[type].verified++; }); return grouped; } explainConfidence(score, discrepancies) { if (score >= 0.9) return 'High confidence - all claims verified'; if (score >= 0.7) return 'Good confidence - most claims verified'; if (score >= 0.5) return 'Moderate confidence - some discrepancies found'; if (score >= 0.3) return 'Low confidence - significant discrepancies'; return `Very low confidence - found ${discrepancies.length} discrepancies`; } generateEvidenceBasedSummary(verification) { const { confidenceScore, discrepancies } = verification; if (discrepancies.length === 0) { return `Verification complete. All claims verified with ${(confidenceScore * 100).toFixed(0)}% confidence.`; } return `Verification revealed ${discrepancies.length} discrepancies. Confidence: ${(confidenceScore * 100).toFixed(0)}%. ${discrepancies[0].reason}.`; } generateFindings(verification, actualState) { const findings = []; // Add critical findings for discrepancies verification.discrepancies.forEach((discrepancy, index) => { findings.push({ id: `discrepancy-${index}`, type: 'false_positive', severity: 'critical', title: 'Sub-agent claim not verified', description: `Claim "${discrepancy.claim}" contradicted by evidence: ${discrepancy.reason}` }); }); // Add warning findings for actual issues if (actualState.hasConsoleErrors) { findings.push({ id: 'console-errors', type: 'error', severity: 'warning', title: `${actualState.errorCount} console errors detected`, description: 'Evidence shows console errors that need attention' }); } if (actualState.hasNetworkFailures) { findings.push({ id: 'network-failures', type: 'network', severity: 'warning', title: `${actualState.failedRequestCount} failed network requests`, description: 'Network requests are failing which may impact functionality' }); } return findings; } generateSuggestions(verification, actualState) { const suggestions = []; if (verification.confidenceScore < 0.5) { suggestions.push({ id: 'use-hybrid', title: 'Use hybrid orchestrator for manual verification', description: 'Low confidence in results suggests manual verification needed', priority: 'high', effort: 'small' }); } if (actualState.hasConsoleErrors) { suggestions.push({ id: 'fix-errors', title: 'Fix console errors', description: 'Address the console errors detected by evidence gathering', priority: 'high', effort: 'medium' }); } return suggestions; } generateVerifiedRecommendations(verification, actualState) { const recommendations = []; if (verification.confidenceScore > 0.8) { if (actualState.hasConsoleErrors) { recommendations.push('Fix console errors first - they are verified to exist'); } if (actualState.hasNetworkFailures) { recommendations.push('Investigate failed network requests'); } } if (verification.confidenceScore < 0.5) { recommendations.push('Run manual verification due to conflicting evidence'); recommendations.push('Use hybrid_orchestrator for direct tool access'); } if (verification.discrepancies.length > 0) { recommendations.push('Sub-agent results appear unreliable - trust evidence instead'); } return recommendations; } selectSubAgent(task, state) { if (state.hasConsoleErrors) return 'error_investigation_agent'; if (state.isPerformanceIssue) return 'performance_agent'; if (state.hasNetworkFailures) return 'network_debug_agent'; return 'debug_agent'; } async callSubAgent(agent, task) { // Mock sub-agent call return { agent, summary: 'Sub-agent analysis complete', findings: {} }; } async executeTool(tool, params) { // Use the real tool executor if available if (this.toolExecutor) { console.error(`🔧 Orchestrator executing tool: ${tool} with params:`, params); const result = await this.toolExecutor.execute(tool, params, {}); console.error(`✅ Tool ${tool} result:`, result); return result; } // Fallback if no executor is set console.warn(`⚠️ No tool executor available for ${tool}`); return { error: 'Tool executor not initialized' }; } // Method to inject the tool executor setToolExecutor(executor) { this.toolExecutor = executor; } countElements(snapshot) { // Mock element counting return 100; } } //# sourceMappingURL=verification-first-orchestrator.js.map