airefactor #19

Merged
mstoeck3 merged 25 commits from airefactor into main 2025-08-17 22:59:31 +00:00
3 changed files with 240 additions and 63 deletions
Showing only changes of commit 5ecbabea90 - Show all commits

View File

@ -422,9 +422,7 @@ class AIQueryInterface {
return Object.values(this.elements).some(el => el !== null); return Object.values(this.elements).some(el => el !== null);
} }
setupEventListeners() { setupEventListeners() {
console.log('[AI Interface] Setting up event listeners...');
this.elements.toggleSwitch?.addEventListener('click', () => this.toggleMode()); this.elements.toggleSwitch?.addEventListener('click', () => this.toggleMode());
this.elements.workflowLabel?.addEventListener('click', () => this.setMode('workflow')); this.elements.workflowLabel?.addEventListener('click', () => this.setMode('workflow'));
this.elements.toolLabel?.addEventListener('click', () => this.setMode('tool')); this.elements.toolLabel?.addEventListener('click', () => this.setMode('tool'));
@ -438,13 +436,10 @@ class AIQueryInterface {
}); });
if (this.elements.submitBtn) { if (this.elements.submitBtn) {
console.log('[AI Interface] Attaching click handler to submit button');
this.elements.submitBtn.addEventListener('click', () => { this.elements.submitBtn.addEventListener('click', () => {
console.log('[AI Interface] Submit button clicked!');
this.handleSubmit(); this.handleSubmit();
}); });
} else { } else {
console.error('[AI Interface] Submit button not found!');
} }
this.elements.dismissSuggestions?.addEventListener('click', () => this.hideSmartPrompting()); this.elements.dismissSuggestions?.addEventListener('click', () => this.hideSmartPrompting());
@ -654,9 +649,7 @@ class AIQueryInterface {
if (this.elements.smartHint) showElement(this.elements.smartHint); if (this.elements.smartHint) showElement(this.elements.smartHint);
} }
async handleSubmit() { async handleSubmit() {
console.log('[AI Interface] handleSubmit called');
const query = this.elements.input.value.trim(); const query = this.elements.input.value.trim();
if (!query) { if (!query) {
@ -1084,7 +1077,6 @@ class AIQueryInterface {
if (downloadBtn && !downloadBtn.hasAttribute('data-setup')) { if (downloadBtn && !downloadBtn.hasAttribute('data-setup')) {
downloadBtn.setAttribute('data-setup', 'true'); downloadBtn.setAttribute('data-setup', 'true');
downloadBtn.addEventListener('click', () => this.downloadResults()); downloadBtn.addEventListener('click', () => this.downloadResults());
console.log('[AI Interface] Download button setup complete');
} }
}; };
@ -1119,7 +1111,6 @@ class AIQueryInterface {
qualityMetrics: { qualityMetrics: {
avgProcessingTime: 0, avgProcessingTime: 0,
confidenceDistribution: { high: 0, medium: 0, low: 0 } confidenceDistribution: { high: 0, medium: 0, low: 0 }
// Removed aiTransparency
}, },
analysisQuality: 'excellent', analysisQuality: 'excellent',
keyInsights: [ keyInsights: [
@ -1602,25 +1593,33 @@ class AIQueryInterface {
concept_name: bg.concept_name, concept_name: bg.concept_name,
relevance: bg.relevance relevance: bg.relevance
})) || [], })) || [],
contextHistory: [], // This would need to be passed from server if needed contextHistory: [],
embeddingsSimilarities: {} // This would need to be passed from server if needed embeddingsSimilarities: {}
}; };
// Enhanced export structure with proper audit trail handling
const exportData = { const exportData = {
metadata: { metadata: {
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
version: "1.0", version: "1.1", // Increment version for improved structure
toolsDataHash: toolsDataHash, toolsDataHash: toolsDataHash,
aiModel: aiModel, aiModel: aiModel,
aiParameters: aiParameters, aiParameters: aiParameters,
userQuery: inputValue, userQuery: inputValue,
mode: this.currentMode, mode: this.currentMode,
processingStats: processingStats, processingStats: processingStats,
exportedBy: 'ForensicPathways' exportedBy: 'ForensicPathways',
auditTrailVersion: '1.1' // Track audit trail format version
}, },
recommendation: this.currentRecommendation, recommendation: {
auditTrail: this.currentRecommendation.auditTrail || [], // Export recommendation without auditTrail to avoid duplication
rawContext: rawContext ...this.currentRecommendation,
auditTrail: undefined // Remove from recommendation as it's at top level
},
auditTrail: this.currentRecommendation.auditTrail || [], // Extract to top level
rawContext: rawContext,
// Add validation checksum for integrity
checksum: this.calculateDataChecksum(this.currentRecommendation)
}; };
const blob = new Blob([JSON.stringify(exportData, null, 2)], { const blob = new Blob([JSON.stringify(exportData, null, 2)], {
@ -1634,17 +1633,46 @@ class AIQueryInterface {
a.click(); a.click();
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
console.log('[AI Interface] Analysis downloaded with real metadata:', { console.log('[AI Interface] Analysis downloaded with enhanced structure:', {
version: '1.1',
aiModel, aiModel,
toolsDataHash: toolsDataHash.slice(0, 8) + '...', toolsDataHash: toolsDataHash.slice(0, 8) + '...',
tokensUsed: aiParameters.totalTokensUsed, tokensUsed: aiParameters.totalTokensUsed,
auditEntries: exportData.auditTrail.length auditEntries: exportData.auditTrail.length,
checksum: exportData.checksum.slice(0, 8) + '...'
}); });
} }
calculateDataChecksum(data) {
if (!data) return 'empty';
try {
// Simple checksum based on key data properties
const keyData = {
recommendedToolsCount: data.recommended_tools?.length || 0,
backgroundKnowledgeCount: data.background_knowledge?.length || 0,
hasScenarioAnalysis: !!(data.scenario_analysis || data.problem_analysis),
hasApproach: !!data.investigation_approach,
processingTimeMs: data.processingStats?.processingTimeMs || 0
};
const dataString = JSON.stringify(keyData);
let hash = 0;
for (let i = 0; i < dataString.length; i++) {
const char = dataString.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32-bit integer
}
return Math.abs(hash).toString(36);
} catch (error) {
console.error('[AI Interface] Checksum calculation failed:', error);
return 'error';
}
}
validateUploadStructure(data) { validateUploadStructure(data) {
try { try {
return !!( const isValid = !!(
data && data &&
typeof data === 'object' && typeof data === 'object' &&
data.metadata && data.metadata &&
@ -1652,8 +1680,32 @@ class AIQueryInterface {
typeof data.metadata.timestamp === 'string' && typeof data.metadata.timestamp === 'string' &&
data.recommendation && data.recommendation &&
typeof data.recommendation === 'object' && typeof data.recommendation === 'object' &&
Array.isArray(data.auditTrail) Array.isArray(data.auditTrail) // Audit trail at top level
); );
if (!isValid) {
return false;
}
// Enhanced validation for audit trail structure
if (data.auditTrail.length > 0) {
const sampleEntry = data.auditTrail[0];
const hasRequiredFields = !!(
sampleEntry &&
typeof sampleEntry === 'object' &&
typeof sampleEntry.timestamp === 'number' &&
typeof sampleEntry.phase === 'string' &&
typeof sampleEntry.action === 'string' &&
typeof sampleEntry.confidence === 'number'
);
if (!hasRequiredFields) {
console.warn('[AI Interface] Audit trail entries missing required fields');
return false;
}
}
return true;
} catch (error) { } catch (error) {
console.error('[AI Interface] Structure validation error:', error); console.error('[AI Interface] Structure validation error:', error);
return false; return false;
@ -1666,7 +1718,11 @@ class AIQueryInterface {
this.showUploadedBanner(data.metadata); this.showUploadedBanner(data.metadata);
this.currentRecommendation = data.recommendation; // Fix: Ensure audit trail is available in recommendation for restoreAIResults
this.currentRecommendation = {
...data.recommendation,
auditTrail: data.auditTrail // Restore audit trail to recommendation object
};
this.showResults(); this.showResults();
@ -1757,7 +1813,15 @@ class AIQueryInterface {
throw new Error('Ungültiges Analyse-Dateiformat'); throw new Error('Ungültiges Analyse-Dateiformat');
} }
console.log('[AI Interface] Valid previous analysis file uploaded'); // Store audit trail separately for restore function
this.uploadedAuditTrail = data.auditTrail;
console.log('[AI Interface] Valid previous analysis file uploaded:', {
version: data.metadata.version || '1.0',
auditEntries: data.auditTrail?.length || 0,
toolsCount: data.recommendation.recommended_tools?.length || 0,
checksum: data.checksum?.slice(0, 8) + '...' || 'none'
});
this.hideResults(); this.hideResults();
this.hideError(); this.hideError();
@ -2218,15 +2282,20 @@ class AIQueryInterface {
if (this.currentRecommendation && this.elements.results) { if (this.currentRecommendation && this.elements.results) {
this.showResults(); this.showResults();
if (this.currentRecommendation.auditTrail) { // Check both locations for audit trail for backward compatibility
const auditTrail = this.currentRecommendation.auditTrail || this.uploadedAuditTrail;
if (auditTrail && Array.isArray(auditTrail) && auditTrail.length > 0) {
setTimeout(() => { setTimeout(() => {
try { try {
this.renderAuditTrail(this.currentRecommendation.auditTrail); this.renderAuditTrail(auditTrail);
console.log('[AI Interface] Audit trail restored successfully'); console.log('[AI Interface] Audit trail restored successfully:', auditTrail.length, 'entries');
} catch (error) { } catch (error) {
console.error('[AI Interface] Audit trail restore failed:', error); console.error('[AI Interface] Audit trail restore failed:', error);
} }
}, 100); }, 100);
} else {
console.warn('[AI Interface] No audit trail available for restore');
} }
this.hideLoading(); this.hideLoading();

View File

@ -510,9 +510,7 @@ if (aiAuthRequired) {
}, 500); }, 500);
}; };
function handleSharedURL() { function handleSharedURL() {
console.log('[SHARE] Handling shared URL:', window.location.search);
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
const toolParam = urlParams.get('tool'); const toolParam = urlParams.get('tool');
const viewParam = urlParams.get('view'); const viewParam = urlParams.get('view');

View File

@ -1,4 +1,4 @@
// src/utils/aiPipeline.ts - Fixed with accurate audit data and meaningful confidence // src/utils/aiPipeline.ts - Fixed to remove hardcoded values and improve dynamics
import { getCompressedToolsDataForAI, getDataVersion } from './dataService.js'; import { getCompressedToolsDataForAI, getDataVersion } from './dataService.js';
import { aiService } from './aiService.js'; import { aiService } from './aiService.js';
import { toolSelector, type SelectionContext } from './toolSelector.js'; import { toolSelector, type SelectionContext } from './toolSelector.js';
@ -77,6 +77,12 @@ interface PipelineContext {
}>; }>;
seenToolNames: Set<string>; seenToolNames: Set<string>;
embeddingsSimilarities: Map<string, number>; embeddingsSimilarities: Map<string, number>;
// Add phase metadata for dynamic phase handling
phaseMetadata?: {
phases: any[];
criticalPhaseIds: string[];
phaseComplexity: Map<string, number>;
};
} }
class AIPipeline { class AIPipeline {
@ -95,7 +101,7 @@ class AIPipeline {
} }
}; };
console.log('[AI-PIPELINE] Initialized with improved audit accuracy'); console.log('[AI-PIPELINE] Initialized with dynamic phase handling');
} }
async processQuery(userQuery: string, mode: string): Promise<AnalysisResult> { async processQuery(userQuery: string, mode: string): Promise<AnalysisResult> {
@ -121,17 +127,16 @@ class AIPipeline {
maxContextLength: this.config.maxContextTokens, maxContextLength: this.config.maxContextTokens,
currentContextLength: 0, currentContextLength: 0,
seenToolNames: new Set<string>(), seenToolNames: new Set<string>(),
embeddingsSimilarities: new Map<string, number>() embeddingsSimilarities: new Map<string, number>(),
// Initialize phase metadata dynamically
phaseMetadata: this.initializePhaseMetadata(toolsData.phases)
}; };
// Skip initialization audit entry - it doesn't add transparency value
console.log('[AI-PIPELINE] Phase 1: Tool candidate selection'); console.log('[AI-PIPELINE] Phase 1: Tool candidate selection');
const candidateSelectionStart = Date.now(); const candidateSelectionStart = Date.now();
const candidateData = await toolSelector.getIntelligentCandidates(userQuery, toolsData, mode, context); const candidateData = await toolSelector.getIntelligentCandidates(userQuery, toolsData, mode, context);
// Calculate meaningful confidence for tool selection
const selectionConfidence = this.calculateToolSelectionConfidence( const selectionConfidence = this.calculateToolSelectionConfidence(
candidateData.tools.length, candidateData.tools.length,
toolsData.tools.length, toolsData.tools.length,
@ -197,8 +202,6 @@ class AIPipeline {
const recommendation = this.buildRecommendation(context, mode, finalResult.content); const recommendation = this.buildRecommendation(context, mode, finalResult.content);
// Skip completion audit entry - it doesn't add transparency value
const processingStats = { const processingStats = {
embeddingsUsed: embeddingsService.isEnabled(), embeddingsUsed: embeddingsService.isEnabled(),
candidatesFromEmbeddings: candidateData.tools.length, candidatesFromEmbeddings: candidateData.tools.length,
@ -242,6 +245,55 @@ class AIPipeline {
} }
} }
private initializePhaseMetadata(phases: any[]): {
phases: any[];
criticalPhaseIds: string[];
phaseComplexity: Map<string, number>;
} {
if (!phases || !Array.isArray(phases)) {
console.warn('[AI-PIPELINE] No phases data available, using fallback');
return {
phases: [],
criticalPhaseIds: [],
phaseComplexity: new Map()
};
}
// Dynamically determine critical phases based on typical_tools or key_activities
const criticalPhaseIds = phases
.filter(phase => {
const typicalToolsCount = phase.typical_tools?.length || 0;
const keyActivitiesCount = phase.key_activities?.length || 0;
// Consider phases with many tools or activities as critical
return typicalToolsCount >= 3 || keyActivitiesCount >= 2;
})
.map(phase => phase.id);
// Calculate phase complexity based on metadata
const phaseComplexity = new Map<string, number>();
phases.forEach(phase => {
let complexity = 1; // Base complexity
if (phase.typical_tools?.length > 5) complexity += 1;
if (phase.key_activities?.length > 3) complexity += 1;
if (phase.description?.length > 100) complexity += 1;
phaseComplexity.set(phase.id, complexity);
});
console.log('[AI-PIPELINE] Initialized phase metadata:', {
totalPhases: phases.length,
criticalPhases: criticalPhaseIds.length,
avgComplexity: Array.from(phaseComplexity.values()).reduce((sum, c) => sum + c, 0) / phases.length
});
return {
phases,
criticalPhaseIds,
phaseComplexity
};
}
private calculateToolSelectionConfidence( private calculateToolSelectionConfidence(
selectedCount: number, selectedCount: number,
totalCount: number, totalCount: number,
@ -252,26 +304,22 @@ class AIPipeline {
const selectionRatio = selectedCount / totalCount; const selectionRatio = selectedCount / totalCount;
// Good selection ratio (5-20% is optimal)
if (selectionRatio >= 0.05 && selectionRatio <= 0.20) { if (selectionRatio >= 0.05 && selectionRatio <= 0.20) {
confidence += 25; confidence += 25;
} else if (selectionRatio < 0.05) { } else if (selectionRatio < 0.05) {
confidence += 15; // Very selective confidence += 15;
} else if (selectionRatio > 0.30) { } else if (selectionRatio > 0.30) {
confidence -= 15; // Too inclusive confidence -= 15;
} }
// Embeddings method bonus
if (method.includes('embeddings')) { if (method.includes('embeddings')) {
confidence += 15; confidence += 15;
} }
// Concepts also selected
if (conceptsCount > 0) { if (conceptsCount > 0) {
confidence += 10; confidence += 10;
} }
// Reasonable absolute numbers
if (selectedCount >= 8 && selectedCount <= 25) { if (selectedCount >= 8 && selectedCount <= 25) {
confidence += 10; confidence += 10;
} }
@ -301,12 +349,12 @@ class AIPipeline {
const selections = await toolSelector.selectToolsForPhase(context.userQuery, phase, phaseTools, context); const selections = await toolSelector.selectToolsForPhase(context.userQuery, phase, phaseTools, context);
// Calculate meaningful confidence based on phase selection quality
const phaseConfidence = this.calculatePhaseSelectionConfidence( const phaseConfidence = this.calculatePhaseSelectionConfidence(
selections.length, selections.length,
phaseTools.length, phaseTools.length,
phase.id, phase.id,
selections selections,
context.phaseMetadata
); );
auditService.addEntry( auditService.addEntry(
@ -341,7 +389,10 @@ class AIPipeline {
const moderatedTaskRelevance = this.moderateTaskRelevance(sel.taskRelevance); const moderatedTaskRelevance = this.moderateTaskRelevance(sel.taskRelevance);
const priority = this.derivePriorityFromScore(moderatedTaskRelevance); const priority = this.derivePriorityFromScore(moderatedTaskRelevance);
this.addToolToSelection(context, tool, phase.id, priority, sel.justification, moderatedTaskRelevance, sel.limitations); // Generate dynamic limitations based on context
const dynamicLimitations = this.generateDynamicLimitations(tool, phase, sel);
this.addToolToSelection(context, tool, phase.id, priority, sel.justification, moderatedTaskRelevance, dynamicLimitations);
auditService.addEntry( auditService.addEntry(
'tool-reasoning', 'tool-reasoning',
@ -354,7 +405,7 @@ class AIPipeline {
}, },
{ {
justification: sel.justification, justification: sel.justification,
limitations: sel.limitations, limitations: dynamicLimitations,
addedToPhase: phase.name addedToPhase: phase.name
}, },
moderatedTaskRelevance || 70, moderatedTaskRelevance || 70,
@ -384,19 +435,24 @@ class AIPipeline {
selectedCount: number, selectedCount: number,
availableCount: number, availableCount: number,
phaseId: string, phaseId: string,
selections: any[] selections: any[],
phaseMetadata?: {
phases: any[];
criticalPhaseIds: string[];
phaseComplexity: Map<string, number>;
}
): number { ): number {
let confidence = 60; let confidence = 60;
// Phase-specific expectations // Use dynamic phase metadata instead of hardcoded values
const criticalPhases = ['acquisition', 'examination', 'analysis']; const isCritical = phaseMetadata?.criticalPhaseIds.includes(phaseId) || false;
const isCritical = criticalPhases.includes(phaseId); const phaseComplexity = phaseMetadata?.phaseComplexity.get(phaseId) || 1;
// Selection made // Selection made
if (selectedCount > 0) { if (selectedCount > 0) {
confidence += 20; confidence += 20;
} else { } else {
return 30; // No selection is concerning return 30;
} }
// Selection ratio (for phases, 20-50% is reasonable) // Selection ratio (for phases, 20-50% is reasonable)
@ -404,14 +460,19 @@ class AIPipeline {
if (ratio >= 0.2 && ratio <= 0.5) { if (ratio >= 0.2 && ratio <= 0.5) {
confidence += 15; confidence += 15;
} else if (ratio < 0.2 && selectedCount >= 1) { } else if (ratio < 0.2 && selectedCount >= 1) {
confidence += 10; // Selective is ok confidence += 10;
} }
// Critical phases should have adequate tools // Dynamic critical phase handling
if (isCritical && selectedCount >= 2) { if (isCritical && selectedCount >= 2) {
confidence += 10; confidence += 10;
} }
// Phase complexity factor
if (phaseComplexity > 2 && selectedCount >= phaseComplexity) {
confidence += 5;
}
// Quality of selections (based on task relevance) // Quality of selections (based on task relevance)
const avgRelevance = selections.length > 0 ? const avgRelevance = selections.length > 0 ?
selections.reduce((sum, s) => sum + (s.taskRelevance || 70), 0) / selections.length : 0; selections.reduce((sum, s) => sum + (s.taskRelevance || 70), 0) / selections.length : 0;
@ -425,6 +486,35 @@ class AIPipeline {
return Math.min(95, Math.max(30, confidence)); return Math.min(95, Math.max(30, confidence));
} }
private generateDynamicLimitations(tool: any, phase: any, selection: any): string[] {
const limitations: string[] = [];
// Add existing limitations if provided
if (selection.limitations && Array.isArray(selection.limitations)) {
limitations.push(...selection.limitations);
}
// Generate context-aware limitations
if (tool.type === 'software' && !tool.projectUrl) {
limitations.push('Installation und Konfiguration erforderlich');
}
if (tool.skillLevel === 'expert') {
limitations.push('Erfordert spezialisierte Kenntnisse');
}
if (tool.license === 'Proprietary') {
limitations.push('Kommerzielle Lizenz erforderlich');
}
// Phase-specific limitations
if (phase.id === 'acquisition' && tool.type === 'method') {
limitations.push('Sorgfältige Dokumentation für Chain of Custody erforderlich');
}
return limitations.slice(0, 3); // Limit to 3 most relevant
}
private async processToolMode( private async processToolMode(
context: PipelineContext, context: PipelineContext,
completedTasks: number, completedTasks: number,
@ -582,7 +672,6 @@ class AIPipeline {
}; };
} }
// This is the fix for "0 tools added" - use the actual valid tools
const actualToolsAdded = validTools.map(tool => tool.name); const actualToolsAdded = validTools.map(tool => tool.name);
for (const tool of validTools) { for (const tool of validTools) {
@ -610,6 +699,9 @@ class AIPipeline {
moderatedTaskRelevance = this.moderateTaskRelevance(75); moderatedTaskRelevance = this.moderateTaskRelevance(75);
} }
// Generate dynamic limitations instead of hardcoded ones
const dynamicLimitations = this.generateCompletionLimitations(tool, phase, selection);
this.addToolToSelection( this.addToolToSelection(
context, context,
tool, tool,
@ -617,16 +709,15 @@ class AIPipeline {
'medium', 'medium',
detailedJustification, detailedJustification,
moderatedTaskRelevance, moderatedTaskRelevance,
['Nachträgliche Ergänzung via semantische Phasensuche mit KI-Bewertung'] dynamicLimitations
); );
console.log('[AI-PIPELINE] Added phase completion tool with AI reasoning:', tool.name); console.log('[AI-PIPELINE] Added phase completion tool with AI reasoning:', tool.name);
} }
// Use the actual tools added for audit
auditService.addPhaseCompletion( auditService.addPhaseCompletion(
phase.id, phase.id,
actualToolsAdded, // This ensures correct count actualToolsAdded,
selection.completionReasoning || `${actualToolsAdded.length} Tools für ${phase.name} hinzugefügt`, selection.completionReasoning || `${actualToolsAdded.length} Tools für ${phase.name} hinzugefügt`,
phaseStart, phaseStart,
{ {
@ -660,6 +751,29 @@ class AIPipeline {
} }
} }
private generateCompletionLimitations(tool: any, phase: any, selection: any): string[] {
const limitations: string[] = [];
// Context-specific limitation for completion tools
limitations.push('Nachträgliche Ergänzung - ursprünglich nicht als Hauptmethode identifiziert');
// Tool-specific limitations
if (tool.skillLevel === 'expert') {
limitations.push('Erfordert Expertenwissen für optimale Nutzung');
}
if (tool.type === 'software' && !tool.projectUrl) {
limitations.push('Zusätzliche Setup-Zeit erforderlich');
}
// Phase-specific context
if (phase.typical_tools && !phase.typical_tools.includes(tool.name)) {
limitations.push(`Nicht typisch für ${phase.name}-Phase - alternative Anwendung`);
}
return limitations.slice(0, 3);
}
private moderateTaskRelevance(taskRelevance: number): number { private moderateTaskRelevance(taskRelevance: number): number {
if (typeof taskRelevance !== 'number') { if (typeof taskRelevance !== 'number') {
return 70; return 70;
@ -904,7 +1018,6 @@ class AIPipeline {
'background-knowledge' 'background-knowledge'
); );
// Calculate confidence based on quality of selections
const selectionQualityBonus = this.calculateKnowledgeSelectionBonus(context.backgroundKnowledge, availableConcepts); const selectionQualityBonus = this.calculateKnowledgeSelectionBonus(context.backgroundKnowledge, availableConcepts);
const finalConfidence = Math.min(95, responseConfidence + selectionQualityBonus); const finalConfidence = Math.min(95, responseConfidence + selectionQualityBonus);
@ -951,13 +1064,11 @@ class AIPipeline {
bonus += 10; bonus += 10;
} }
// Good selection ratio (10-30% of available concepts)
const ratio = selectedKnowledge.length / availableConcepts.length; const ratio = selectedKnowledge.length / availableConcepts.length;
if (ratio >= 0.1 && ratio <= 0.3) { if (ratio >= 0.1 && ratio <= 0.3) {
bonus += 15; bonus += 15;
} }
// Quality reasoning provided
const hasGoodReasonings = selectedKnowledge.some(bk => const hasGoodReasonings = selectedKnowledge.some(bk =>
bk.relevance && bk.relevance.length > 30 bk.relevance && bk.relevance.length > 30
); );
@ -983,7 +1094,6 @@ class AIPipeline {
'final-recommendations' 'final-recommendations'
); );
// Calculate bonus based on context quality
const contextBonus = this.calculateSynthesisBonus(selectedToolNames, context); const contextBonus = this.calculateSynthesisBonus(selectedToolNames, context);
const finalConfidence = Math.min(95, confidence + contextBonus); const finalConfidence = Math.min(95, confidence + contextBonus);