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
JavaScript
/**
* 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