phase 2
This commit is contained in:
		
							parent
							
								
									0c7c502b03
								
							
						
					
					
						commit
						77f09ed399
					
				@ -217,7 +217,6 @@ const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<script type="module" define:vars={{ tools, phases, domainAgnosticSoftware }}>
 | 
					<script type="module" define:vars={{ tools, phases, domainAgnosticSoftware }}>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Utility functions (inline to avoid import issues)
 | 
					 | 
				
			||||||
function showElement(element) {
 | 
					function showElement(element) {
 | 
				
			||||||
  if (element) {
 | 
					  if (element) {
 | 
				
			||||||
    element.style.display = 'block';
 | 
					    element.style.display = 'block';
 | 
				
			||||||
@ -908,38 +907,535 @@ class AIQueryInterface {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  renderAuditTrail(rawAuditTrail) {
 | 
					  renderAuditTrail(rawAuditTrail) {
 | 
				
			||||||
    // Simplified audit trail rendering - remove complex processor
 | 
					 | 
				
			||||||
    const container = document.getElementById('audit-trail-container');
 | 
					    const container = document.getElementById('audit-trail-container');
 | 
				
			||||||
    if (!container || !rawAuditTrail || !Array.isArray(rawAuditTrail)) return;
 | 
					    if (!container || !rawAuditTrail || !Array.isArray(rawAuditTrail)) {
 | 
				
			||||||
 | 
					      console.warn('[AI Interface] Cannot render audit trail: invalid container or data');
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    const totalTime = rawAuditTrail.reduce((sum, entry) => sum + (entry.processingTimeMs || 0), 0);
 | 
					    console.log('[AI Interface] Rendering comprehensive audit trail with', rawAuditTrail.length, 'entries');
 | 
				
			||||||
    const avgConfidence = rawAuditTrail.length > 0 
 | 
					    
 | 
				
			||||||
      ? Math.round(rawAuditTrail.reduce((sum, entry) => sum + (entry.confidence || 0), 0) / rawAuditTrail.length)
 | 
					    try {
 | 
				
			||||||
      : 0;
 | 
					      // Calculate audit statistics
 | 
				
			||||||
 | 
					      const stats = this.calculateAuditStats(rawAuditTrail);
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      container.innerHTML = `
 | 
					      container.innerHTML = `
 | 
				
			||||||
        <div class="audit-trail-container">
 | 
					        <div class="audit-trail-container">
 | 
				
			||||||
        <div class="audit-trail-header">
 | 
					          <div class="audit-trail-header clickable" onclick="this.parentElement.querySelector('.audit-trail-details').classList.toggle('collapsed'); this.querySelector('.toggle-icon').style.transform = this.parentElement.querySelector('.audit-trail-details').classList.contains('collapsed') ? 'rotate(0deg)' : 'rotate(90deg)';">
 | 
				
			||||||
            <div class="audit-trail-title">
 | 
					            <div class="audit-trail-title">
 | 
				
			||||||
              <div class="audit-icon">
 | 
					              <div class="audit-icon">
 | 
				
			||||||
              <div class="audit-icon-gradient">✓</div>
 | 
					                <div class="audit-icon-gradient">🔍</div>
 | 
				
			||||||
                <h4>KI-Entscheidungspfad</h4>
 | 
					                <h4>KI-Entscheidungspfad</h4>
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
              <div class="audit-stats">
 | 
					              <div class="audit-stats">
 | 
				
			||||||
                <div class="stat-item">
 | 
					                <div class="stat-item">
 | 
				
			||||||
                <span>${formatDuration(totalTime)}</span>
 | 
					                  <div class="stat-dot stat-time"></div>
 | 
				
			||||||
 | 
					                  <span>${formatDuration(stats.totalTime)}</span>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div class="stat-item">
 | 
					                <div class="stat-item">
 | 
				
			||||||
                <span>${avgConfidence}% Vertrauen</span>
 | 
					                  <div class="stat-dot" style="background-color: ${getConfidenceColor(stats.avgConfidence)};"></div>
 | 
				
			||||||
 | 
					                  <span>${stats.avgConfidence}% Vertrauen</span>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div class="stat-item">
 | 
					                <div class="stat-item">
 | 
				
			||||||
                  <span>${rawAuditTrail.length} Schritte</span>
 | 
					                  <span>${rawAuditTrail.length} Schritte</span>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					            <svg class="toggle-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="transform: rotate(90deg);">
 | 
				
			||||||
 | 
					              <polyline points="9 18 15 12 9 6"/>
 | 
				
			||||||
 | 
					            </svg>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="audit-trail-details">
 | 
				
			||||||
 | 
					            <!-- Audit Summary -->
 | 
				
			||||||
 | 
					            <div class="audit-summary">
 | 
				
			||||||
 | 
					              <div class="summary-header">📊 Analyse-Zusammenfassung</div>
 | 
				
			||||||
 | 
					              <div class="summary-grid">
 | 
				
			||||||
 | 
					                <div class="summary-stat">
 | 
				
			||||||
 | 
					                  <div class="summary-value success">${stats.aiDecisionCount}</div>
 | 
				
			||||||
 | 
					                  <div class="summary-label">KI-Entscheidungen</div>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <div class="summary-stat">
 | 
				
			||||||
 | 
					                  <div class="summary-value ${stats.embeddingsUsageCount > 0 ? 'success' : 'warning'}">${stats.embeddingsUsageCount}</div>
 | 
				
			||||||
 | 
					                  <div class="summary-label">Semantische Suchen</div>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <div class="summary-stat">
 | 
				
			||||||
 | 
					                  <div class="summary-value success">${stats.toolSelectionCount}</div>
 | 
				
			||||||
 | 
					                  <div class="summary-label">Tool-Auswahlen</div>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              
 | 
				
			||||||
 | 
					              <div class="insights-section">
 | 
				
			||||||
 | 
					                ${stats.qualityMetrics.aiTransparency >= 80 ? `
 | 
				
			||||||
 | 
					                  <div class="insights-header success">✅ Hohe Transparenz</div>
 | 
				
			||||||
 | 
					                  <ul class="insights-list">
 | 
				
			||||||
 | 
					                    <li>${stats.qualityMetrics.aiTransparency}% der Entscheidungen mit nachvollziehbarer Begründung</li>
 | 
				
			||||||
 | 
					                    <li>Durchschnittliche Verarbeitungszeit: ${formatDuration(stats.qualityMetrics.avgProcessingTime)}</li>
 | 
				
			||||||
 | 
					                  </ul>
 | 
				
			||||||
 | 
					                ` : `
 | 
				
			||||||
 | 
					                  <div class="insights-header warning">⚠️ Transparenz-Hinweise</div>
 | 
				
			||||||
 | 
					                  <ul class="insights-list">
 | 
				
			||||||
 | 
					                    <li>Nur ${stats.qualityMetrics.aiTransparency}% der Entscheidungen vollständig dokumentiert</li>
 | 
				
			||||||
 | 
					                    <li>Einige KI-Entscheidungen ohne detaillierte Begründung</li>
 | 
				
			||||||
 | 
					                  </ul>
 | 
				
			||||||
 | 
					                `}
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <!-- Process Flow -->
 | 
				
			||||||
 | 
					            <div class="audit-process-flow">
 | 
				
			||||||
 | 
					              ${this.renderPhaseGroups(rawAuditTrail, stats)}
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <!-- Download/Upload Controls -->
 | 
				
			||||||
 | 
					            <div class="ai-results-controls" style="margin-top: 1.5rem; text-align: center; border-top: 1px solid var(--color-border); padding-top: 1rem;">
 | 
				
			||||||
 | 
					              <button id="download-results-btn" class="btn btn-secondary" style="margin-right: 0.5rem;">
 | 
				
			||||||
 | 
					                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 0.5rem;">
 | 
				
			||||||
 | 
					                  <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
 | 
				
			||||||
 | 
					                  <polyline points="7 10 12 15 17 10"/>
 | 
				
			||||||
 | 
					                  <line x1="12" y1="15" x2="12" y2="3"/>
 | 
				
			||||||
 | 
					                </svg>
 | 
				
			||||||
 | 
					                Analyse herunterladen
 | 
				
			||||||
 | 
					              </button>
 | 
				
			||||||
 | 
					              
 | 
				
			||||||
 | 
					              <label for="upload-results" class="btn btn-secondary">
 | 
				
			||||||
 | 
					                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 0.5rem;">
 | 
				
			||||||
 | 
					                  <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
 | 
				
			||||||
 | 
					                  <polyline points="17 8 12 3 7 8"/>
 | 
				
			||||||
 | 
					                  <line x1="12" y1="3" x2="12" y2="15"/>
 | 
				
			||||||
 | 
					                </svg>
 | 
				
			||||||
 | 
					                Analyse hochladen
 | 
				
			||||||
 | 
					                <input type="file" id="upload-results" accept=".json" style="display: none;" />
 | 
				
			||||||
 | 
					              </label>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <!-- Technical Details Toggle -->
 | 
				
			||||||
 | 
					            <div class="technical-toggle">
 | 
				
			||||||
 | 
					              <button class="technical-toggle-btn" onclick="this.parentElement.parentElement.querySelector('.technical-details').classList.toggle('collapsed'); this.textContent = this.parentElement.parentElement.querySelector('.technical-details').classList.contains('collapsed') ? 'Technische Details anzeigen' : 'Technische Details verbergen';">
 | 
				
			||||||
 | 
					                Technische Details anzeigen
 | 
				
			||||||
 | 
					              </button>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <!-- Technical Details -->
 | 
				
			||||||
 | 
					            <div class="technical-details collapsed">
 | 
				
			||||||
 | 
					              ${this.renderTechnicalDetails(rawAuditTrail)}
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      `;
 | 
					      `;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Setup download functionality
 | 
				
			||||||
 | 
					      this.setupDownloadUpload();
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					      console.error('[AI Interface] Error rendering audit trail:', error);
 | 
				
			||||||
 | 
					      container.innerHTML = `
 | 
				
			||||||
 | 
					        <div class="audit-trail-container">
 | 
				
			||||||
 | 
					          <div class="audit-trail-header">
 | 
				
			||||||
 | 
					            <div class="audit-trail-title">
 | 
				
			||||||
 | 
					              <div class="audit-icon">
 | 
				
			||||||
 | 
					                <div class="audit-icon-gradient">⚠️</div>
 | 
				
			||||||
 | 
					                <h4>Audit Trail Fehler</h4>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div class="audit-trail-details">
 | 
				
			||||||
 | 
					            <p style="color: var(--color-error); padding: 1rem;">
 | 
				
			||||||
 | 
					              Fehler beim Rendern des Audit Trails. Details in der Konsole.
 | 
				
			||||||
 | 
					            </p>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      `;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  calculateAuditStats(auditTrail) {
 | 
				
			||||||
 | 
					    if (!auditTrail || auditTrail.length === 0) {
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        totalTime: 0,
 | 
				
			||||||
 | 
					        avgConfidence: 0,
 | 
				
			||||||
 | 
					        stepCount: 0,
 | 
				
			||||||
 | 
					        aiDecisionCount: 0,
 | 
				
			||||||
 | 
					        embeddingsUsageCount: 0,
 | 
				
			||||||
 | 
					        toolSelectionCount: 0,
 | 
				
			||||||
 | 
					        qualityMetrics: {
 | 
				
			||||||
 | 
					          avgProcessingTime: 0,
 | 
				
			||||||
 | 
					          aiTransparency: 0
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const totalTime = auditTrail.reduce((sum, entry) => sum + (entry.processingTimeMs || 0), 0);
 | 
				
			||||||
 | 
					    const validConfidenceEntries = auditTrail.filter(entry => typeof entry.confidence === 'number');
 | 
				
			||||||
 | 
					    const avgConfidence = validConfidenceEntries.length > 0 
 | 
				
			||||||
 | 
					      ? Math.round(validConfidenceEntries.reduce((sum, entry) => sum + entry.confidence, 0) / validConfidenceEntries.length)
 | 
				
			||||||
 | 
					      : 0;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    const aiDecisionCount = auditTrail.filter(entry => entry.action === 'ai-decision').length;
 | 
				
			||||||
 | 
					    const embeddingsUsageCount = auditTrail.filter(entry => entry.metadata?.embeddingsUsed).length;
 | 
				
			||||||
 | 
					    const toolSelectionCount = auditTrail.filter(entry => entry.action === 'selection-decision').length;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    const avgProcessingTime = auditTrail.length > 0 ? totalTime / auditTrail.length : 0;
 | 
				
			||||||
 | 
					    const aiTransparency = auditTrail.length > 0 ? 
 | 
				
			||||||
 | 
					      (auditTrail.filter(entry => entry.metadata?.aiPrompt || entry.metadata?.reasoning).length / auditTrail.length) * 100 : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      totalTime,
 | 
				
			||||||
 | 
					      avgConfidence,
 | 
				
			||||||
 | 
					      stepCount: auditTrail.length,
 | 
				
			||||||
 | 
					      aiDecisionCount,
 | 
				
			||||||
 | 
					      embeddingsUsageCount,
 | 
				
			||||||
 | 
					      toolSelectionCount,
 | 
				
			||||||
 | 
					      qualityMetrics: {
 | 
				
			||||||
 | 
					        avgProcessingTime,
 | 
				
			||||||
 | 
					        aiTransparency: Math.round(aiTransparency)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  renderPhaseGroups(auditTrail, stats) {
 | 
				
			||||||
 | 
					    // Group audit entries by phase
 | 
				
			||||||
 | 
					    const phaseGroups = new Map();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    auditTrail.forEach(entry => {
 | 
				
			||||||
 | 
					      const phase = entry.phase || 'unknown';
 | 
				
			||||||
 | 
					      if (!phaseGroups.has(phase)) {
 | 
				
			||||||
 | 
					        phaseGroups.set(phase, []);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // FIXED: Remove non-null assertion, use proper null checking
 | 
				
			||||||
 | 
					      const phaseEntries = phaseGroups.get(phase);
 | 
				
			||||||
 | 
					      if (phaseEntries) {
 | 
				
			||||||
 | 
					        phaseEntries.push(entry);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let html = '';
 | 
				
			||||||
 | 
					    let groupIndex = 0;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    for (const [phaseName, entries] of phaseGroups) {
 | 
				
			||||||
 | 
					      const isLastPhase = groupIndex === phaseGroups.size - 1;
 | 
				
			||||||
 | 
					      const phaseAvgConfidence = entries.reduce((sum, e) => sum + (e.confidence || 0), 0) / entries.length;
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      html += `
 | 
				
			||||||
 | 
					        <div class="phase-group ${isLastPhase ? 'last-phase' : ''}">
 | 
				
			||||||
 | 
					          <div class="phase-header" style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1rem;">
 | 
				
			||||||
 | 
					            <div style="display: flex; align-items: center; gap: 0.75rem;">
 | 
				
			||||||
 | 
					              <div class="phase-icon">${this.getPhaseIcon(phaseName)}</div>
 | 
				
			||||||
 | 
					              <div class="phase-name">${this.getPhaseDisplayName(phaseName)}</div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="phase-divider"></div>
 | 
				
			||||||
 | 
					            <div class="phase-stats">
 | 
				
			||||||
 | 
					              <div class="confidence-bar">
 | 
				
			||||||
 | 
					                <div class="confidence-fill" style="width: ${phaseAvgConfidence}%; background-color: ${getConfidenceColor(phaseAvgConfidence)};"></div>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              <span class="confidence-text">${Math.round(phaseAvgConfidence)}%</span>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          
 | 
				
			||||||
 | 
					          <div class="phase-entries">
 | 
				
			||||||
 | 
					            ${entries.map(entry => this.renderAuditEntry(entry)).join('')}
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      `;
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      groupIndex++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return html;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  renderAuditEntry(entry) {
 | 
				
			||||||
 | 
					    const confidenceColor = getConfidenceColor(entry.confidence || 0);
 | 
				
			||||||
 | 
					    const processingTime = formatDuration(entry.processingTimeMs || 0);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return `
 | 
				
			||||||
 | 
					      <div class="audit-entry">
 | 
				
			||||||
 | 
					        <div class="entry-main">
 | 
				
			||||||
 | 
					          <div class="entry-action">${this.getActionDisplayName(entry.action)}</div>
 | 
				
			||||||
 | 
					          <div class="entry-meta">
 | 
				
			||||||
 | 
					            <div class="confidence-indicator" style="background-color: ${confidenceColor};"></div>
 | 
				
			||||||
 | 
					            <span class="confidence-value">${entry.confidence || 0}%</span>
 | 
				
			||||||
 | 
					            <span class="processing-time">${processingTime}</span>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        ${this.renderEntryDetails(entry)}
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    `;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  renderEntryDetails(entry) {
 | 
				
			||||||
 | 
					    const details = [];
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // AI-specific details
 | 
				
			||||||
 | 
					    if (entry.action === 'ai-decision' && entry.metadata?.reasoning) {
 | 
				
			||||||
 | 
					      details.push(`<div class="detail-item"><strong>Begründung:</strong> ${truncateText(entry.metadata.reasoning, 200)}</div>`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Tool selection details
 | 
				
			||||||
 | 
					    if (entry.action === 'selection-decision') {
 | 
				
			||||||
 | 
					      if (entry.metadata?.selectedToolsCount && entry.metadata?.availableToolsCount) {
 | 
				
			||||||
 | 
					        details.push(`<div class="detail-item"><strong>Auswahl:</strong> ${entry.metadata.selectedToolsCount} von ${entry.metadata.availableToolsCount} Tools</div>`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (entry.metadata?.selectionMethod) {
 | 
				
			||||||
 | 
					        details.push(`<div class="detail-item"><strong>Methode:</strong> ${entry.metadata.selectionMethod}</div>`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Embeddings details
 | 
				
			||||||
 | 
					    if (entry.metadata?.embeddingsUsed && entry.metadata?.totalMatches) {
 | 
				
			||||||
 | 
					      details.push(`<div class="detail-item"><strong>Semantische Treffer:</strong> ${entry.metadata.totalMatches}</div>`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Confidence factors
 | 
				
			||||||
 | 
					    if (entry.metadata?.confidenceFactors?.length > 0) {
 | 
				
			||||||
 | 
					      const factors = entry.metadata.confidenceFactors.slice(0, 2).join(', ');
 | 
				
			||||||
 | 
					      details.push(`<div class="detail-item"><strong>Faktoren:</strong> ${factors}</div>`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if (details.length === 0) return '';
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return `
 | 
				
			||||||
 | 
					      <div class="entry-details">
 | 
				
			||||||
 | 
					        ${details.join('')}
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    `;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  renderTechnicalDetails(auditTrail) {
 | 
				
			||||||
 | 
					    return auditTrail.map(entry => `
 | 
				
			||||||
 | 
					      <div class="technical-entry">
 | 
				
			||||||
 | 
					        <div class="technical-header">
 | 
				
			||||||
 | 
					          <div class="technical-phase">${entry.phase}/${entry.action}</div>
 | 
				
			||||||
 | 
					          <div class="technical-time">${new Date(entry.timestamp).toLocaleTimeString('de-DE')}</div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="technical-content">
 | 
				
			||||||
 | 
					          ${entry.metadata?.aiModel ? `<div class="technical-row">Model: ${entry.metadata.aiModel}</div>` : ''}
 | 
				
			||||||
 | 
					          ${entry.metadata?.promptTokens ? `<div class="technical-row">Tokens: ${entry.metadata.promptTokens}/${entry.metadata.completionTokens}</div>` : ''}
 | 
				
			||||||
 | 
					          ${entry.metadata?.microTaskType ? `<div class="technical-row">Task: ${entry.metadata.microTaskType}</div>` : ''}
 | 
				
			||||||
 | 
					          ${entry.metadata?.selectionMethod ? `<div class="technical-row">Method: ${entry.metadata.selectionMethod}</div>` : ''}
 | 
				
			||||||
 | 
					          <div class="technical-row">Confidence: ${entry.confidence}% (${entry.processingTimeMs}ms)</div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    `).join('');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getPhaseIcon(phase) {
 | 
				
			||||||
 | 
					    const icons = {
 | 
				
			||||||
 | 
					      'initialization': '🚀',
 | 
				
			||||||
 | 
					      'tool-selection': '🔧',
 | 
				
			||||||
 | 
					      'contextual-analysis': '🧠',
 | 
				
			||||||
 | 
					      'workflow-phase': '⚡',
 | 
				
			||||||
 | 
					      'tool-reasoning': '💭',
 | 
				
			||||||
 | 
					      'knowledge-synthesis': '📚',
 | 
				
			||||||
 | 
					      'confidence-scoring': '📊',
 | 
				
			||||||
 | 
					      'phase-completion': '✅',
 | 
				
			||||||
 | 
					      'completion': '🎯',
 | 
				
			||||||
 | 
					      'embeddings': '🔍',
 | 
				
			||||||
 | 
					      'unknown': '❓'
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return icons[phase] || icons['unknown'];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getPhaseDisplayName(phase) {
 | 
				
			||||||
 | 
					    const names = {
 | 
				
			||||||
 | 
					      'initialization': 'Initialisierung',
 | 
				
			||||||
 | 
					      'tool-selection': 'Tool-Auswahl',
 | 
				
			||||||
 | 
					      'contextual-analysis': 'Kontext-Analyse',
 | 
				
			||||||
 | 
					      'workflow-phase': 'Workflow-Phase',
 | 
				
			||||||
 | 
					      'tool-reasoning': 'Tool-Bewertung',
 | 
				
			||||||
 | 
					      'knowledge-synthesis': 'Wissens-Synthese',
 | 
				
			||||||
 | 
					      'confidence-scoring': 'Vertrauenswertung',
 | 
				
			||||||
 | 
					      'phase-completion': 'Phasen-Vervollständigung',
 | 
				
			||||||
 | 
					      'completion': 'Abschluss',
 | 
				
			||||||
 | 
					      'embeddings': 'Semantische Suche',
 | 
				
			||||||
 | 
					      'unknown': 'Unbekannt'
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return names[phase] || phase;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getActionDisplayName(action) {
 | 
				
			||||||
 | 
					    const actions = {
 | 
				
			||||||
 | 
					      'pipeline-start': 'Analyse gestartet',
 | 
				
			||||||
 | 
					      'selection-decision': 'Tools ausgewählt',
 | 
				
			||||||
 | 
					      'ai-decision': 'KI-Entscheidung',
 | 
				
			||||||
 | 
					      'phase-tool-selection': 'Phasen-Tools evaluiert',
 | 
				
			||||||
 | 
					      'tool-added-to-phase': 'Tool zur Phase hinzugefügt',
 | 
				
			||||||
 | 
					      'concept-selection': 'Konzepte ausgewählt',
 | 
				
			||||||
 | 
					      'tool-confidence': 'Vertrauen berechnet',
 | 
				
			||||||
 | 
					      'phase-enhancement': 'Phase vervollständigt',
 | 
				
			||||||
 | 
					      'similarity-search': 'Ähnlichkeitssuche',
 | 
				
			||||||
 | 
					      'pipeline-end': 'Analyse abgeschlossen'
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return actions[action] || action;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  setupDownloadUpload() {
 | 
				
			||||||
 | 
					    const downloadBtn = document.getElementById('download-results-btn');
 | 
				
			||||||
 | 
					    const uploadInput = document.getElementById('upload-results');
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if (downloadBtn) {
 | 
				
			||||||
 | 
					      downloadBtn.addEventListener('click', () => this.downloadResults());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if (uploadInput) {
 | 
				
			||||||
 | 
					      uploadInput.addEventListener('change', (event) => {
 | 
				
			||||||
 | 
					        // FIXED: Remove TypeScript casting
 | 
				
			||||||
 | 
					        const files = event.target.files;
 | 
				
			||||||
 | 
					        const file = files ? files[0] : null;
 | 
				
			||||||
 | 
					        if (file) {
 | 
				
			||||||
 | 
					          this.handleFileUpload(file);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  downloadResults() {
 | 
				
			||||||
 | 
					    if (!this.currentRecommendation) {
 | 
				
			||||||
 | 
					      alert('Keine Analyse zum Herunterladen verfügbar.');
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // FIXED: Use safer property access
 | 
				
			||||||
 | 
					    const inputValue = this.elements.input ? this.elements.input.value : '';
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    const exportData = {
 | 
				
			||||||
 | 
					      metadata: {
 | 
				
			||||||
 | 
					        timestamp: new Date().toISOString(),
 | 
				
			||||||
 | 
					        version: "1.0",
 | 
				
			||||||
 | 
					        toolsDataHash: "current", // This would come from dataService
 | 
				
			||||||
 | 
					        aiModel: "claude-sonnet-4", // This would come from aiService
 | 
				
			||||||
 | 
					        aiParameters: {},
 | 
				
			||||||
 | 
					        userQuery: inputValue,
 | 
				
			||||||
 | 
					        mode: this.currentMode,
 | 
				
			||||||
 | 
					        processingStats: {},
 | 
				
			||||||
 | 
					        exportedBy: 'ForensicPathways'
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      recommendation: this.currentRecommendation,
 | 
				
			||||||
 | 
					      auditTrail: this.currentRecommendation.auditTrail || [],
 | 
				
			||||||
 | 
					      rawContext: {
 | 
				
			||||||
 | 
					        selectedTools: [],
 | 
				
			||||||
 | 
					        backgroundKnowledge: [],
 | 
				
			||||||
 | 
					        contextHistory: [],
 | 
				
			||||||
 | 
					        embeddingsSimilarities: {}
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    const blob = new Blob([JSON.stringify(exportData, null, 2)], {
 | 
				
			||||||
 | 
					      type: 'application/json'
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    const url = URL.createObjectURL(blob);
 | 
				
			||||||
 | 
					    const a = document.createElement('a');
 | 
				
			||||||
 | 
					    a.href = url;
 | 
				
			||||||
 | 
					    a.download = `forensic-ai-analysis-${Date.now()}.json`;
 | 
				
			||||||
 | 
					    a.click();
 | 
				
			||||||
 | 
					    URL.revokeObjectURL(url);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    console.log('[AI Interface] Analysis downloaded');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async handleFileUpload(file) {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      // Security validation
 | 
				
			||||||
 | 
					      if (file.size > 10 * 1024 * 1024) {
 | 
				
			||||||
 | 
					        throw new Error('Datei zu groß (max 10MB)');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      if (!file.name.endsWith('.json')) {
 | 
				
			||||||
 | 
					        throw new Error('Ungültiger Dateityp - nur JSON-Dateien werden unterstützt');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      const text = await file.text();
 | 
				
			||||||
 | 
					      let data;
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        data = JSON.parse(text);
 | 
				
			||||||
 | 
					      } catch (error) {
 | 
				
			||||||
 | 
					        throw new Error('Ungültiges JSON-Format');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      if (!this.validateUploadStructure(data)) {
 | 
				
			||||||
 | 
					        throw new Error('Ungültiges Analyse-Dateiformat');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      console.log('[AI Interface] Valid analysis file uploaded');
 | 
				
			||||||
 | 
					      this.displayUploadedResults(data);
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					      console.error('[AI Interface] Upload failed:', error);
 | 
				
			||||||
 | 
					      alert(`Upload fehlgeschlagen: ${error.message}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  validateUploadStructure(data) {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      return !!(
 | 
				
			||||||
 | 
					        data &&
 | 
				
			||||||
 | 
					        typeof data === 'object' &&
 | 
				
			||||||
 | 
					        data.metadata &&
 | 
				
			||||||
 | 
					        typeof data.metadata === 'object' &&
 | 
				
			||||||
 | 
					        typeof data.metadata.timestamp === 'string' &&
 | 
				
			||||||
 | 
					        data.recommendation &&
 | 
				
			||||||
 | 
					        typeof data.recommendation === 'object' &&
 | 
				
			||||||
 | 
					        Array.isArray(data.auditTrail)
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					      console.error('[AI Interface] Structure validation error:', error);
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  displayUploadedResults(data) {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      // Show upload banner
 | 
				
			||||||
 | 
					      this.showUploadedBanner(data.metadata);
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // Restore interface state
 | 
				
			||||||
 | 
					      this.currentRecommendation = data.recommendation;
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // Display the uploaded analysis
 | 
				
			||||||
 | 
					      this.showResults();
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // Update the recommendation display
 | 
				
			||||||
 | 
					      if (data.metadata.mode === 'workflow') {
 | 
				
			||||||
 | 
					        this.displayWorkflowResults(data.recommendation, data.metadata.userQuery);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        this.displayToolResults(data.recommendation, data.metadata.userQuery);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // Render the uploaded audit trail
 | 
				
			||||||
 | 
					      setTimeout(() => {
 | 
				
			||||||
 | 
					        this.renderAuditTrail(data.auditTrail);
 | 
				
			||||||
 | 
					      }, 100);
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      console.log('[AI Interface] Uploaded analysis displayed successfully');
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					      console.error('[AI Interface] Error displaying uploaded results:', error);
 | 
				
			||||||
 | 
					      alert('Fehler beim Anzeigen der hochgeladenen Analyse');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  showUploadedBanner(metadata) {
 | 
				
			||||||
 | 
					    const banner = `
 | 
				
			||||||
 | 
					      <div class="uploaded-results-banner" style="background: var(--color-bg-secondary); border: 1px solid var(--color-warning); border-radius: 0.5rem; padding: 1rem; margin-bottom: 1rem; display: flex; align-items: center; gap: 1rem;">
 | 
				
			||||||
 | 
					        <div style="font-size: 1.5rem;">📁</div>
 | 
				
			||||||
 | 
					        <div style="flex: 1;">
 | 
				
			||||||
 | 
					          <strong style="color: var(--color-warning);">Hochgeladene Analyse</strong>
 | 
				
			||||||
 | 
					          <div style="font-size: 0.875rem; color: var(--color-text-secondary); margin-top: 0.25rem;">
 | 
				
			||||||
 | 
					            Erstellt: ${new Date(metadata.timestamp).toLocaleString('de-DE')} | 
 | 
				
			||||||
 | 
					            Modus: ${metadata.mode} | 
 | 
				
			||||||
 | 
					            ${metadata.toolsDataHash ? `Hash: ${metadata.toolsDataHash.slice(0, 8)}...` : ''}
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <button onclick="this.parentElement.remove()" style="background: none; border: none; color: var(--color-text-secondary); cursor: pointer; font-size: 1.25rem;">×</button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    `;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // FIXED: Add null checking
 | 
				
			||||||
 | 
					    if (this.elements && this.elements.results) {
 | 
				
			||||||
 | 
					      this.elements.results.insertAdjacentHTML('afterbegin', banner);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  renderHeader(title, query) {
 | 
					  renderHeader(title, query) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
---
 | 
					---
 | 
				
			||||||
import { createToolSlug } from '../utils/toolHelpers.js';
 | 
					import { createToolSlug } from '../utils/clientUtils.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface Props {
 | 
					export interface Props {
 | 
				
			||||||
  toolName: string;
 | 
					  toolName: string;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,11 @@
 | 
				
			|||||||
// src/utils/aiPipeline.ts - Refactored
 | 
					// src/utils/aiPipeline.ts - Enhanced with comprehensive audit logging
 | 
				
			||||||
import { getCompressedToolsDataForAI } 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';
 | 
				
			||||||
import { confidenceScoring, type AnalysisContext } from './confidenceScoring.js';
 | 
					import { confidenceScoring, type AnalysisContext } from './confidenceScoring.js';
 | 
				
			||||||
import { embeddingsService } from './embeddings.js';
 | 
					import { embeddingsService } from './embeddings.js';
 | 
				
			||||||
import { auditService, type AuditEntry } from './auditService.js';
 | 
					import { auditService, type AuditEntry } from './auditService.js';
 | 
				
			||||||
 | 
					import { JSONParser } from './jsonUtils.js'; // FIXED: Use centralized JSON parsing
 | 
				
			||||||
import { getPrompt } from '../config/prompts.js';
 | 
					import { getPrompt } from '../config/prompts.js';
 | 
				
			||||||
import 'dotenv/config';
 | 
					import 'dotenv/config';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -20,6 +21,11 @@ interface MicroTaskResult {
 | 
				
			|||||||
  processingTimeMs: number;
 | 
					  processingTimeMs: number;
 | 
				
			||||||
  success: boolean;
 | 
					  success: boolean;
 | 
				
			||||||
  error?: string;
 | 
					  error?: string;
 | 
				
			||||||
 | 
					  aiUsage?: {
 | 
				
			||||||
 | 
					    promptTokens?: number;
 | 
				
			||||||
 | 
					    completionTokens?: number;
 | 
				
			||||||
 | 
					    totalTokens?: number;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface AnalysisResult {
 | 
					interface AnalysisResult {
 | 
				
			||||||
@ -32,6 +38,8 @@ interface AnalysisResult {
 | 
				
			|||||||
    microTasksCompleted: number;
 | 
					    microTasksCompleted: number;
 | 
				
			||||||
    microTasksFailed: number;
 | 
					    microTasksFailed: number;
 | 
				
			||||||
    contextContinuityUsed: boolean;
 | 
					    contextContinuityUsed: boolean;
 | 
				
			||||||
 | 
					    totalAITokensUsed: number;
 | 
				
			||||||
 | 
					    auditEntriesGenerated: number;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -64,6 +72,7 @@ interface PipelineContext {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class AIPipeline {
 | 
					class AIPipeline {
 | 
				
			||||||
  private config: PipelineConfig;
 | 
					  private config: PipelineConfig;
 | 
				
			||||||
 | 
					  private totalTokensUsed: number = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor() {
 | 
					  constructor() {
 | 
				
			||||||
    this.config = {
 | 
					    this.config = {
 | 
				
			||||||
@ -79,6 +88,7 @@ class AIPipeline {
 | 
				
			|||||||
    const startTime = Date.now();
 | 
					    const startTime = Date.now();
 | 
				
			||||||
    let completedTasks = 0;
 | 
					    let completedTasks = 0;
 | 
				
			||||||
    let failedTasks = 0;
 | 
					    let failedTasks = 0;
 | 
				
			||||||
 | 
					    this.totalTokensUsed = 0;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    console.log('[AI-PIPELINE] Starting', mode, 'analysis pipeline');
 | 
					    console.log('[AI-PIPELINE] Starting', mode, 'analysis pipeline');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -87,6 +97,8 @@ class AIPipeline {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const toolsData = await getCompressedToolsDataForAI();
 | 
					      const toolsData = await getCompressedToolsDataForAI();
 | 
				
			||||||
 | 
					      const aiConfig = aiService.getConfig();
 | 
				
			||||||
 | 
					      const toolsDataHash = getDataVersion?.() || 'unknown';
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      const context: PipelineContext = {
 | 
					      const context: PipelineContext = {
 | 
				
			||||||
        userQuery,
 | 
					        userQuery,
 | 
				
			||||||
@ -99,67 +111,119 @@ class AIPipeline {
 | 
				
			|||||||
        embeddingsSimilarities: new Map<string, number>()
 | 
					        embeddingsSimilarities: new Map<string, number>()
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Phase 1: Get intelligent tool candidates
 | 
					      // AUDIT: Pipeline initialization
 | 
				
			||||||
 | 
					      auditService.addEntry(
 | 
				
			||||||
 | 
					        'initialization',
 | 
				
			||||||
 | 
					        'pipeline-start',
 | 
				
			||||||
 | 
					        { 
 | 
				
			||||||
 | 
					          userQuery: this.truncateForAudit(userQuery), 
 | 
				
			||||||
 | 
					          mode, 
 | 
				
			||||||
 | 
					          toolsDataLoaded: !!toolsData,
 | 
				
			||||||
 | 
					          aiConfig: { model: aiConfig.model }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        { 
 | 
				
			||||||
 | 
					          totalAvailableTools: toolsData.tools.length,
 | 
				
			||||||
 | 
					          totalAvailableConcepts: toolsData.concepts.length,
 | 
				
			||||||
 | 
					          embeddingsEnabled: embeddingsService.isEnabled()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        90,
 | 
				
			||||||
 | 
					        startTime,
 | 
				
			||||||
 | 
					        { 
 | 
				
			||||||
 | 
					          toolsDataHash,
 | 
				
			||||||
 | 
					          aiModel: aiConfig.model,
 | 
				
			||||||
 | 
					          embeddingsUsed: embeddingsService.isEnabled(),
 | 
				
			||||||
 | 
					          pipelineVersion: '2.0-enhanced'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Phase 1: Get intelligent tool candidates with enhanced logging
 | 
				
			||||||
      console.log('[AI-PIPELINE] Phase 1: Tool candidate selection');
 | 
					      console.log('[AI-PIPELINE] Phase 1: Tool candidate selection');
 | 
				
			||||||
 | 
					      const candidateSelectionStart = Date.now();
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
      const candidateData = await toolSelector.getIntelligentCandidates(userQuery, toolsData, mode, context);
 | 
					      const candidateData = await toolSelector.getIntelligentCandidates(userQuery, toolsData, mode, context);
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
 | 
					      // AUDIT: Tool candidate selection
 | 
				
			||||||
 | 
					      auditService.addToolSelection(
 | 
				
			||||||
 | 
					        candidateData.tools.map(t => t.name),
 | 
				
			||||||
 | 
					        toolsData.tools.map(t => t.name),
 | 
				
			||||||
 | 
					        candidateData.selectionMethod,
 | 
				
			||||||
 | 
					        85,
 | 
				
			||||||
 | 
					        candidateSelectionStart,
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          embeddingsUsed: embeddingsService.isEnabled(),
 | 
				
			||||||
 | 
					          totalCandidatesFound: candidateData.tools.length + candidateData.concepts.length,
 | 
				
			||||||
 | 
					          selectionMethod: candidateData.selectionMethod,
 | 
				
			||||||
 | 
					          reductionRatio: candidateData.tools.length / toolsData.tools.length
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
      context.filteredData = candidateData;
 | 
					      context.filteredData = candidateData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this.addAuditEntry(
 | 
					      // Phase 2: Contextual analysis micro-tasks with enhanced logging
 | 
				
			||||||
        'initialization',
 | 
					 | 
				
			||||||
        'pipeline-start',
 | 
					 | 
				
			||||||
        { userQuery, mode, toolsDataLoaded: !!toolsData },
 | 
					 | 
				
			||||||
        { candidateTools: candidateData.tools.length, candidateConcepts: candidateData.concepts.length },
 | 
					 | 
				
			||||||
        90,
 | 
					 | 
				
			||||||
        startTime,
 | 
					 | 
				
			||||||
        { selectionMethod: candidateData.selectionMethod }
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Phase 2: Contextual analysis micro-tasks
 | 
					 | 
				
			||||||
      console.log('[AI-PIPELINE] Phase 2: Contextual analysis');
 | 
					      console.log('[AI-PIPELINE] Phase 2: Contextual analysis');
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      const analysisResult = await this.analyzeScenario(context);
 | 
					      const analysisResult = await this.analyzeScenario(context, startTime);
 | 
				
			||||||
      if (analysisResult.success) completedTasks++; else failedTasks++;
 | 
					      if (analysisResult.success) completedTasks++; else failedTasks++;
 | 
				
			||||||
 | 
					      this.trackTokenUsage(analysisResult.aiUsage);
 | 
				
			||||||
      await this.delay(this.config.microTaskDelay);
 | 
					      await this.delay(this.config.microTaskDelay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const approachResult = await this.generateApproach(context);
 | 
					      const approachResult = await this.generateApproach(context, startTime);
 | 
				
			||||||
      if (approachResult.success) completedTasks++; else failedTasks++;
 | 
					      if (approachResult.success) completedTasks++; else failedTasks++;
 | 
				
			||||||
 | 
					      this.trackTokenUsage(approachResult.aiUsage);
 | 
				
			||||||
      await this.delay(this.config.microTaskDelay);
 | 
					      await this.delay(this.config.microTaskDelay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const considerationsResult = await this.generateCriticalConsiderations(context);
 | 
					      const considerationsResult = await this.generateCriticalConsiderations(context, startTime);
 | 
				
			||||||
      if (considerationsResult.success) completedTasks++; else failedTasks++;
 | 
					      if (considerationsResult.success) completedTasks++; else failedTasks++;
 | 
				
			||||||
 | 
					      this.trackTokenUsage(considerationsResult.aiUsage);
 | 
				
			||||||
      await this.delay(this.config.microTaskDelay);
 | 
					      await this.delay(this.config.microTaskDelay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Phase 3: Tool-specific analysis
 | 
					      // Phase 3: Tool-specific analysis with enhanced logging
 | 
				
			||||||
      console.log('[AI-PIPELINE] Phase 3: Tool-specific analysis');
 | 
					      console.log('[AI-PIPELINE] Phase 3: Tool-specific analysis');
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      if (mode === 'workflow') {
 | 
					      if (mode === 'workflow') {
 | 
				
			||||||
        await this.processWorkflowMode(context, toolsData, completedTasks, failedTasks);
 | 
					        const workflowResults = await this.processWorkflowMode(context, toolsData, completedTasks, failedTasks, startTime);
 | 
				
			||||||
 | 
					        completedTasks = workflowResults.completed;
 | 
				
			||||||
 | 
					        failedTasks = workflowResults.failed;
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        await this.processToolMode(context, completedTasks, failedTasks);
 | 
					        const toolResults = await this.processToolMode(context, completedTasks, failedTasks, startTime);
 | 
				
			||||||
 | 
					        completedTasks = toolResults.completed;
 | 
				
			||||||
 | 
					        failedTasks = toolResults.failed;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Phase 4: Knowledge and finalization
 | 
					      // Phase 4: Knowledge and finalization with enhanced logging
 | 
				
			||||||
      console.log('[AI-PIPELINE] Phase 4: Knowledge synthesis');
 | 
					      console.log('[AI-PIPELINE] Phase 4: Knowledge synthesis');
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      const knowledgeResult = await this.selectBackgroundKnowledge(context);
 | 
					      const knowledgeResult = await this.selectBackgroundKnowledge(context, startTime);
 | 
				
			||||||
      if (knowledgeResult.success) completedTasks++; else failedTasks++;
 | 
					      if (knowledgeResult.success) completedTasks++; else failedTasks++;
 | 
				
			||||||
 | 
					      this.trackTokenUsage(knowledgeResult.aiUsage);
 | 
				
			||||||
      await this.delay(this.config.microTaskDelay);
 | 
					      await this.delay(this.config.microTaskDelay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const finalResult = await this.generateFinalRecommendations(context);
 | 
					      const finalResult = await this.generateFinalRecommendations(context, startTime);
 | 
				
			||||||
      if (finalResult.success) completedTasks++; else failedTasks++;
 | 
					      if (finalResult.success) completedTasks++; else failedTasks++;
 | 
				
			||||||
 | 
					      this.trackTokenUsage(finalResult.aiUsage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Build final recommendation
 | 
					      // Build final recommendation
 | 
				
			||||||
      const recommendation = this.buildRecommendation(context, mode, finalResult.content);
 | 
					      const recommendation = this.buildRecommendation(context, mode, finalResult.content);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this.addAuditEntry(
 | 
					      // AUDIT: Pipeline completion
 | 
				
			||||||
 | 
					      auditService.addEntry(
 | 
				
			||||||
        'completion',
 | 
					        'completion',
 | 
				
			||||||
        'pipeline-end',
 | 
					        'pipeline-end',
 | 
				
			||||||
        { completedTasks, failedTasks },
 | 
					        { completedTasks, failedTasks, totalTokensUsed: this.totalTokensUsed },
 | 
				
			||||||
        { finalRecommendation: !!recommendation, auditEntriesGenerated: auditService.getCurrentAuditTrail().length },
 | 
					        { 
 | 
				
			||||||
 | 
					          finalRecommendation: !!recommendation, 
 | 
				
			||||||
 | 
					          auditEntriesGenerated: auditService.getCurrentAuditTrail().length,
 | 
				
			||||||
 | 
					          selectedToolsCount: context.selectedTools?.length || 0,
 | 
				
			||||||
 | 
					          backgroundKnowledgeCount: context.backgroundKnowledge?.length || 0
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        completedTasks > failedTasks ? 85 : 60,
 | 
					        completedTasks > failedTasks ? 85 : 60,
 | 
				
			||||||
        startTime,
 | 
					        startTime,
 | 
				
			||||||
        { totalProcessingTimeMs: Date.now() - startTime }
 | 
					        { 
 | 
				
			||||||
 | 
					          totalProcessingTimeMs: Date.now() - startTime,
 | 
				
			||||||
 | 
					          aiModel: aiConfig.model,
 | 
				
			||||||
 | 
					          finalTokenUsage: this.totalTokensUsed,
 | 
				
			||||||
 | 
					          pipelineEfficiency: completedTasks / (completedTasks + failedTasks)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const processingStats = {
 | 
					      const processingStats = {
 | 
				
			||||||
@ -169,7 +233,9 @@ class AIPipeline {
 | 
				
			|||||||
        processingTimeMs: Date.now() - startTime,
 | 
					        processingTimeMs: Date.now() - startTime,
 | 
				
			||||||
        microTasksCompleted: completedTasks,
 | 
					        microTasksCompleted: completedTasks,
 | 
				
			||||||
        microTasksFailed: failedTasks,
 | 
					        microTasksFailed: failedTasks,
 | 
				
			||||||
        contextContinuityUsed: true
 | 
					        contextContinuityUsed: true,
 | 
				
			||||||
 | 
					        totalAITokensUsed: this.totalTokensUsed,
 | 
				
			||||||
 | 
					        auditEntriesGenerated: auditService.getCurrentAuditTrail().length
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      console.log('[AI-PIPELINE] Pipeline completed successfully:', {
 | 
					      console.log('[AI-PIPELINE] Pipeline completed successfully:', {
 | 
				
			||||||
@ -177,7 +243,9 @@ class AIPipeline {
 | 
				
			|||||||
        processingTimeMs: processingStats.processingTimeMs,
 | 
					        processingTimeMs: processingStats.processingTimeMs,
 | 
				
			||||||
        completedTasks,
 | 
					        completedTasks,
 | 
				
			||||||
        failedTasks,
 | 
					        failedTasks,
 | 
				
			||||||
        finalItems: processingStats.finalSelectedItems
 | 
					        finalItems: processingStats.finalSelectedItems,
 | 
				
			||||||
 | 
					        totalTokensUsed: this.totalTokensUsed,
 | 
				
			||||||
 | 
					        auditEntries: processingStats.auditEntriesGenerated
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Finalize audit trail
 | 
					      // Finalize audit trail
 | 
				
			||||||
@ -193,6 +261,18 @@ class AIPipeline {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    } catch (error) {
 | 
					    } catch (error) {
 | 
				
			||||||
      console.error('[AI-PIPELINE] Pipeline failed:', error);
 | 
					      console.error('[AI-PIPELINE] Pipeline failed:', error);
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // AUDIT: Pipeline failure
 | 
				
			||||||
 | 
					      auditService.addEntry(
 | 
				
			||||||
 | 
					        'error',
 | 
				
			||||||
 | 
					        'pipeline-failure',
 | 
				
			||||||
 | 
					        { userQuery: this.truncateForAudit(userQuery), mode },
 | 
				
			||||||
 | 
					        { error: error.message, completedTasks, failedTasks },
 | 
				
			||||||
 | 
					        0,
 | 
				
			||||||
 | 
					        startTime,
 | 
				
			||||||
 | 
					        { errorType: error.constructor.name, totalTokensUsed: this.totalTokensUsed }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
      throw error;
 | 
					      throw error;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -201,23 +281,63 @@ class AIPipeline {
 | 
				
			|||||||
    context: PipelineContext, 
 | 
					    context: PipelineContext, 
 | 
				
			||||||
    toolsData: any, 
 | 
					    toolsData: any, 
 | 
				
			||||||
    completedTasks: number, 
 | 
					    completedTasks: number, 
 | 
				
			||||||
    failedTasks: number
 | 
					    failedTasks: number,
 | 
				
			||||||
  ): Promise<void> {
 | 
					    pipelineStart: number
 | 
				
			||||||
 | 
					  ): Promise<{ completed: number; failed: number }> {
 | 
				
			||||||
    const phases = toolsData.phases || [];
 | 
					    const phases = toolsData.phases || [];
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // Select tools for each phase
 | 
					    // Select tools for each phase with enhanced logging
 | 
				
			||||||
    for (const phase of phases) {
 | 
					    for (const phase of phases) {
 | 
				
			||||||
 | 
					      const phaseStart = Date.now();
 | 
				
			||||||
      const phaseTools = context.filteredData.tools.filter((tool: any) =>
 | 
					      const phaseTools = context.filteredData.tools.filter((tool: any) =>
 | 
				
			||||||
        tool && tool.phases && Array.isArray(tool.phases) && tool.phases.includes(phase.id)
 | 
					        tool && tool.phases && Array.isArray(tool.phases) && tool.phases.includes(phase.id)
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      const selections = await toolSelector.selectToolsForPhase(context.userQuery, phase, phaseTools, context);
 | 
					      const selections = await toolSelector.selectToolsForPhase(context.userQuery, phase, phaseTools, context);
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
 | 
					      // AUDIT: Phase tool selection
 | 
				
			||||||
 | 
					      auditService.addEntry(
 | 
				
			||||||
 | 
					        'workflow-phase',
 | 
				
			||||||
 | 
					        'phase-tool-selection',
 | 
				
			||||||
 | 
					        { 
 | 
				
			||||||
 | 
					          phaseId: phase.id, 
 | 
				
			||||||
 | 
					          phaseName: phase.name, 
 | 
				
			||||||
 | 
					          availableTools: phaseTools.map(t => t.name) 
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        { 
 | 
				
			||||||
 | 
					          selectedTools: selections.map(s => s.toolName),
 | 
				
			||||||
 | 
					          selectionCount: selections.length
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        selections.length > 0 ? 80 : 50,
 | 
				
			||||||
 | 
					        phaseStart,
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          phaseId: phase.id,
 | 
				
			||||||
 | 
					          availableToolsCount: phaseTools.length,
 | 
				
			||||||
 | 
					          selectedToolsCount: selections.length,
 | 
				
			||||||
 | 
					          microTaskType: 'phase-tool-selection'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
      selections.forEach((sel: any) => {
 | 
					      selections.forEach((sel: any) => {
 | 
				
			||||||
        const tool = phaseTools.find((t: any) => t && t.name === sel.toolName);
 | 
					        const tool = phaseTools.find((t: any) => t && t.name === sel.toolName);
 | 
				
			||||||
        if (tool) {
 | 
					        if (tool) {
 | 
				
			||||||
          const priority = this.derivePriorityFromScore(sel.taskRelevance);
 | 
					          const priority = this.derivePriorityFromScore(sel.taskRelevance);
 | 
				
			||||||
          this.addToolToSelection(context, tool, phase.id, priority, sel.justification, sel.taskRelevance, sel.limitations);
 | 
					          this.addToolToSelection(context, tool, phase.id, priority, sel.justification, sel.taskRelevance, sel.limitations);
 | 
				
			||||||
 | 
					          
 | 
				
			||||||
 | 
					          // AUDIT: Individual tool selection reasoning
 | 
				
			||||||
 | 
					          auditService.addEntry(
 | 
				
			||||||
 | 
					            'tool-reasoning',
 | 
				
			||||||
 | 
					            'tool-added-to-phase',
 | 
				
			||||||
 | 
					            { toolName: tool.name, phaseId: phase.id, taskRelevance: sel.taskRelevance },
 | 
				
			||||||
 | 
					            { justification: sel.justification, limitations: sel.limitations },
 | 
				
			||||||
 | 
					            sel.taskRelevance || 70,
 | 
				
			||||||
 | 
					            phaseStart,
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              toolType: tool.type,
 | 
				
			||||||
 | 
					              priority,
 | 
				
			||||||
 | 
					              selectionReasoning: sel.justification
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
@ -225,26 +345,37 @@ class AIPipeline {
 | 
				
			|||||||
      await this.delay(this.config.microTaskDelay);
 | 
					      await this.delay(this.config.microTaskDelay);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // Complete underrepresented phases
 | 
					    // Complete underrepresented phases with enhanced logging
 | 
				
			||||||
    await this.completeUnderrepresentedPhases(context, toolsData);
 | 
					    const completionResult = await this.completeUnderrepresentedPhases(context, toolsData, pipelineStart);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return { completed: completedTasks, failed: failedTasks };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async processToolMode(context: PipelineContext, completedTasks: number, failedTasks: number): Promise<void> {
 | 
					  private async processToolMode(
 | 
				
			||||||
 | 
					    context: PipelineContext, 
 | 
				
			||||||
 | 
					    completedTasks: number, 
 | 
				
			||||||
 | 
					    failedTasks: number,
 | 
				
			||||||
 | 
					    pipelineStart: number
 | 
				
			||||||
 | 
					  ): Promise<{ completed: number; failed: number }> {
 | 
				
			||||||
    const topTools = context.filteredData.tools.slice(0, 3);
 | 
					    const topTools = context.filteredData.tools.slice(0, 3);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    for (let i = 0; i < topTools.length; i++) {
 | 
					    for (let i = 0; i < topTools.length; i++) {
 | 
				
			||||||
      const evaluationResult = await this.evaluateSpecificTool(context, topTools[i], i + 1);
 | 
					      const evaluationResult = await this.evaluateSpecificTool(context, topTools[i], i + 1, pipelineStart);
 | 
				
			||||||
      if (evaluationResult.success) completedTasks++; else failedTasks++;
 | 
					      if (evaluationResult.success) completedTasks++; else failedTasks++;
 | 
				
			||||||
 | 
					      this.trackTokenUsage(evaluationResult.aiUsage);
 | 
				
			||||||
      await this.delay(this.config.microTaskDelay);
 | 
					      await this.delay(this.config.microTaskDelay);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return { completed: completedTasks, failed: failedTasks };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async analyzeScenario(context: PipelineContext): Promise<MicroTaskResult> {
 | 
					  private async analyzeScenario(context: PipelineContext, pipelineStart: number): Promise<MicroTaskResult> {
 | 
				
			||||||
    console.log('[AI-PIPELINE] Micro-task: Scenario analysis');
 | 
					    console.log('[AI-PIPELINE] Micro-task: Scenario analysis');
 | 
				
			||||||
 | 
					    const taskStart = Date.now();
 | 
				
			||||||
    const isWorkflow = context.mode === 'workflow';
 | 
					    const isWorkflow = context.mode === 'workflow';
 | 
				
			||||||
    const prompt = getPrompt('scenarioAnalysis', isWorkflow, context.userQuery);
 | 
					    const prompt = getPrompt('scenarioAnalysis', isWorkflow, context.userQuery);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const result = await this.callMicroTaskAI(prompt, context, 400);
 | 
					    const result = await this.callMicroTaskAI(prompt, context, 400, 'scenario-analysis');
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (result.success) {
 | 
					    if (result.success) {
 | 
				
			||||||
      if (isWorkflow) {
 | 
					      if (isWorkflow) {
 | 
				
			||||||
@ -254,52 +385,109 @@ class AIPipeline {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      this.addToContextHistory(context, `${isWorkflow ? 'Szenario' : 'Problem'}-Analyse: ${result.content.slice(0, 200)}...`);
 | 
					      this.addToContextHistory(context, `${isWorkflow ? 'Szenario' : 'Problem'}-Analyse: ${result.content.slice(0, 200)}...`);
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // AUDIT: Scenario analysis
 | 
				
			||||||
 | 
					      auditService.addAIDecision(
 | 
				
			||||||
 | 
					        'contextual-analysis',
 | 
				
			||||||
 | 
					        prompt,
 | 
				
			||||||
 | 
					        result.content,
 | 
				
			||||||
 | 
					        80,
 | 
				
			||||||
 | 
					        `Generated ${isWorkflow ? 'scenario' : 'problem'} analysis for user query`,
 | 
				
			||||||
 | 
					        taskStart,
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          microTaskType: 'scenario-analysis',
 | 
				
			||||||
 | 
					          analysisType: isWorkflow ? 'scenario' : 'problem',
 | 
				
			||||||
 | 
					          contentLength: result.content.length,
 | 
				
			||||||
 | 
					          ...result.aiUsage
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async generateApproach(context: PipelineContext): Promise<MicroTaskResult> {
 | 
					  private async generateApproach(context: PipelineContext, pipelineStart: number): Promise<MicroTaskResult> {
 | 
				
			||||||
    console.log('[AI-PIPELINE] Micro-task: Investigation approach');
 | 
					    console.log('[AI-PIPELINE] Micro-task: Investigation approach');
 | 
				
			||||||
 | 
					    const taskStart = Date.now();
 | 
				
			||||||
    const isWorkflow = context.mode === 'workflow';
 | 
					    const isWorkflow = context.mode === 'workflow';
 | 
				
			||||||
    const prompt = getPrompt('investigationApproach', isWorkflow, context.userQuery);
 | 
					    const prompt = getPrompt('investigationApproach', isWorkflow, context.userQuery);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const result = await this.callMicroTaskAI(prompt, context, 400);
 | 
					    const result = await this.callMicroTaskAI(prompt, context, 400, 'investigation-approach');
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (result.success) {
 | 
					    if (result.success) {
 | 
				
			||||||
      context.investigationApproach = result.content;
 | 
					      context.investigationApproach = result.content;
 | 
				
			||||||
      this.addToContextHistory(context, `${isWorkflow ? 'Untersuchungs' : 'Lösungs'}ansatz: ${result.content.slice(0, 200)}...`);
 | 
					      this.addToContextHistory(context, `${isWorkflow ? 'Untersuchungs' : 'Lösungs'}ansatz: ${result.content.slice(0, 200)}...`);
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // AUDIT: Investigation approach
 | 
				
			||||||
 | 
					      auditService.addAIDecision(
 | 
				
			||||||
 | 
					        'contextual-analysis',
 | 
				
			||||||
 | 
					        prompt,
 | 
				
			||||||
 | 
					        result.content,
 | 
				
			||||||
 | 
					        75,
 | 
				
			||||||
 | 
					        `Generated ${isWorkflow ? 'investigation' : 'solution'} approach`,
 | 
				
			||||||
 | 
					        taskStart,
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          microTaskType: 'investigation-approach',
 | 
				
			||||||
 | 
					          approachType: isWorkflow ? 'investigation' : 'solution',
 | 
				
			||||||
 | 
					          contentLength: result.content.length,
 | 
				
			||||||
 | 
					          contextHistoryLength: context.contextHistory.length,
 | 
				
			||||||
 | 
					          ...result.aiUsage
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async generateCriticalConsiderations(context: PipelineContext): Promise<MicroTaskResult> {
 | 
					  private async generateCriticalConsiderations(context: PipelineContext, pipelineStart: number): Promise<MicroTaskResult> {
 | 
				
			||||||
    console.log('[AI-PIPELINE] Micro-task: Critical considerations');
 | 
					    console.log('[AI-PIPELINE] Micro-task: Critical considerations');
 | 
				
			||||||
 | 
					    const taskStart = Date.now();
 | 
				
			||||||
    const isWorkflow = context.mode === 'workflow';
 | 
					    const isWorkflow = context.mode === 'workflow';
 | 
				
			||||||
    const prompt = getPrompt('criticalConsiderations', isWorkflow, context.userQuery);
 | 
					    const prompt = getPrompt('criticalConsiderations', isWorkflow, context.userQuery);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const result = await this.callMicroTaskAI(prompt, context, 350);
 | 
					    const result = await this.callMicroTaskAI(prompt, context, 350, 'critical-considerations');
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (result.success) {
 | 
					    if (result.success) {
 | 
				
			||||||
      context.criticalConsiderations = result.content;
 | 
					      context.criticalConsiderations = result.content;
 | 
				
			||||||
      this.addToContextHistory(context, `Kritische Überlegungen: ${result.content.slice(0, 200)}...`);
 | 
					      this.addToContextHistory(context, `Kritische Überlegungen: ${result.content.slice(0, 200)}...`);
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // AUDIT: Critical considerations
 | 
				
			||||||
 | 
					      auditService.addAIDecision(
 | 
				
			||||||
 | 
					        'contextual-analysis',
 | 
				
			||||||
 | 
					        prompt,
 | 
				
			||||||
 | 
					        result.content,
 | 
				
			||||||
 | 
					        70,
 | 
				
			||||||
 | 
					        'Generated critical considerations and constraints',
 | 
				
			||||||
 | 
					        taskStart,
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          microTaskType: 'critical-considerations',
 | 
				
			||||||
 | 
					          contentLength: result.content.length,
 | 
				
			||||||
 | 
					          ...result.aiUsage
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async evaluateSpecificTool(context: PipelineContext, tool: any, rank: number): Promise<MicroTaskResult> {
 | 
					  private async evaluateSpecificTool(
 | 
				
			||||||
 | 
					    context: PipelineContext, 
 | 
				
			||||||
 | 
					    tool: any, 
 | 
				
			||||||
 | 
					    rank: number,
 | 
				
			||||||
 | 
					    pipelineStart: number
 | 
				
			||||||
 | 
					  ): Promise<MicroTaskResult> {
 | 
				
			||||||
    console.log('[AI-PIPELINE] Micro-task: Tool evaluation for:', tool.name);
 | 
					    console.log('[AI-PIPELINE] Micro-task: Tool evaluation for:', tool.name);
 | 
				
			||||||
 | 
					    const taskStart = Date.now();
 | 
				
			||||||
    const existingSelection = context.selectedTools?.find((st: any) => st.tool && st.tool.name === tool.name);
 | 
					    const existingSelection = context.selectedTools?.find((st: any) => st.tool && st.tool.name === tool.name);
 | 
				
			||||||
    const taskRelevance = existingSelection?.taskRelevance || 70;
 | 
					    const taskRelevance = existingSelection?.taskRelevance || 70;
 | 
				
			||||||
    const priority = this.derivePriorityFromScore(taskRelevance);
 | 
					    const priority = this.derivePriorityFromScore(taskRelevance);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    const prompt = getPrompt('toolEvaluation', context.userQuery, tool, rank, taskRelevance);
 | 
					    const prompt = getPrompt('toolEvaluation', context.userQuery, tool, rank, taskRelevance);
 | 
				
			||||||
    const result = await this.callMicroTaskAI(prompt, context, 1000);
 | 
					    const result = await this.callMicroTaskAI(prompt, context, 1000, 'tool-evaluation');
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (result.success) {
 | 
					    if (result.success) {
 | 
				
			||||||
      const evaluation = this.safeParseJSON(result.content, {
 | 
					      // FIXED: Use centralized JSON parsing
 | 
				
			||||||
 | 
					      const evaluation = JSONParser.safeParseJSON(result.content, {
 | 
				
			||||||
        detailed_explanation: 'Evaluation failed',
 | 
					        detailed_explanation: 'Evaluation failed',
 | 
				
			||||||
        implementation_approach: '',
 | 
					        implementation_approach: '',
 | 
				
			||||||
        pros: [],
 | 
					        pros: [],
 | 
				
			||||||
@ -315,13 +503,35 @@ class AIPipeline {
 | 
				
			|||||||
          task_relevance: taskRelevance
 | 
					          task_relevance: taskRelevance
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }, 'evaluation', priority, evaluation.detailed_explanation, taskRelevance, evaluation.limitations);
 | 
					      }, 'evaluation', priority, evaluation.detailed_explanation, taskRelevance, evaluation.limitations);
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // AUDIT: Tool evaluation
 | 
				
			||||||
 | 
					      auditService.addAIDecision(
 | 
				
			||||||
 | 
					        'tool-evaluation',
 | 
				
			||||||
 | 
					        prompt,
 | 
				
			||||||
 | 
					        result.content,
 | 
				
			||||||
 | 
					        taskRelevance,
 | 
				
			||||||
 | 
					        `Evaluated tool ${tool.name} for ${context.mode} mode`,
 | 
				
			||||||
 | 
					        taskStart,
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          microTaskType: 'tool-evaluation',
 | 
				
			||||||
 | 
					          toolName: tool.name,
 | 
				
			||||||
 | 
					          toolType: tool.type,
 | 
				
			||||||
 | 
					          rank,
 | 
				
			||||||
 | 
					          taskRelevance,
 | 
				
			||||||
 | 
					          evaluationParsed: !!evaluation.detailed_explanation,
 | 
				
			||||||
 | 
					          prosCount: evaluation.pros?.length || 0,
 | 
				
			||||||
 | 
					          limitationsCount: evaluation.limitations?.length || 0,
 | 
				
			||||||
 | 
					          ...result.aiUsage
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async selectBackgroundKnowledge(context: PipelineContext): Promise<MicroTaskResult> {
 | 
					  private async selectBackgroundKnowledge(context: PipelineContext, pipelineStart: number): Promise<MicroTaskResult> {
 | 
				
			||||||
    console.log('[AI-PIPELINE] Micro-task: Background knowledge selection');
 | 
					    console.log('[AI-PIPELINE] Micro-task: Background knowledge selection');
 | 
				
			||||||
 | 
					    const taskStart = Date.now();
 | 
				
			||||||
    const availableConcepts = context.filteredData.concepts;
 | 
					    const availableConcepts = context.filteredData.concepts;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (availableConcepts.length === 0) {
 | 
					    if (availableConcepts.length === 0) {
 | 
				
			||||||
@ -335,10 +545,11 @@ class AIPipeline {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const selectedToolNames = context.selectedTools?.map((st: any) => st.tool && st.tool.name).filter(Boolean) || [];
 | 
					    const selectedToolNames = context.selectedTools?.map((st: any) => st.tool && st.tool.name).filter(Boolean) || [];
 | 
				
			||||||
    const prompt = getPrompt('backgroundKnowledgeSelection', context.userQuery, context.mode, selectedToolNames, availableConcepts);
 | 
					    const prompt = getPrompt('backgroundKnowledgeSelection', context.userQuery, context.mode, selectedToolNames, availableConcepts);
 | 
				
			||||||
    const result = await this.callMicroTaskAI(prompt, context, 700);
 | 
					    const result = await this.callMicroTaskAI(prompt, context, 700, 'background-knowledge');
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (result.success) {
 | 
					    if (result.success) {
 | 
				
			||||||
      const selections = this.safeParseJSON(result.content, []);
 | 
					      // FIXED: Use centralized JSON parsing
 | 
				
			||||||
 | 
					      const selections = JSONParser.safeParseJSON(result.content, []);
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      if (Array.isArray(selections)) {
 | 
					      if (Array.isArray(selections)) {
 | 
				
			||||||
        context.backgroundKnowledge = selections.filter((sel: any) =>
 | 
					        context.backgroundKnowledge = selections.filter((sel: any) =>
 | 
				
			||||||
@ -347,21 +558,66 @@ class AIPipeline {
 | 
				
			|||||||
          concept: availableConcepts.find((c: any) => c.name === sel.conceptName),
 | 
					          concept: availableConcepts.find((c: any) => c.name === sel.conceptName),
 | 
				
			||||||
          relevance: sel.relevance
 | 
					          relevance: sel.relevance
 | 
				
			||||||
        }));
 | 
					        }));
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // AUDIT: Background knowledge selection
 | 
				
			||||||
 | 
					        auditService.addEntry(
 | 
				
			||||||
 | 
					          'knowledge-synthesis',
 | 
				
			||||||
 | 
					          'concept-selection',
 | 
				
			||||||
 | 
					          { 
 | 
				
			||||||
 | 
					            availableConcepts: availableConcepts.map(c => c.name),
 | 
				
			||||||
 | 
					            selectedToolsContext: selectedToolNames
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          { 
 | 
				
			||||||
 | 
					            selectedConcepts: context.backgroundKnowledge.map(bk => bk.concept.name),
 | 
				
			||||||
 | 
					            selectionReasonings: context.backgroundKnowledge.map(bk => bk.relevance)
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          context.backgroundKnowledge.length > 0 ? 75 : 50,
 | 
				
			||||||
 | 
					          taskStart,
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            microTaskType: 'background-knowledge',
 | 
				
			||||||
 | 
					            availableConceptsCount: availableConcepts.length,
 | 
				
			||||||
 | 
					            selectedConceptsCount: context.backgroundKnowledge.length,
 | 
				
			||||||
 | 
					            selectionRatio: context.backgroundKnowledge.length / availableConcepts.length,
 | 
				
			||||||
 | 
					            ...result.aiUsage
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async generateFinalRecommendations(context: PipelineContext): Promise<MicroTaskResult> {
 | 
					  private async generateFinalRecommendations(context: PipelineContext, pipelineStart: number): Promise<MicroTaskResult> {
 | 
				
			||||||
    console.log('[AI-PIPELINE] Micro-task: Final recommendations');
 | 
					    console.log('[AI-PIPELINE] Micro-task: Final recommendations');
 | 
				
			||||||
 | 
					    const taskStart = Date.now();
 | 
				
			||||||
    const selectedToolNames = context.selectedTools?.map((st: any) => st.tool && st.tool.name).filter(Boolean) || [];
 | 
					    const selectedToolNames = context.selectedTools?.map((st: any) => st.tool && st.tool.name).filter(Boolean) || [];
 | 
				
			||||||
    const prompt = getPrompt('finalRecommendations', context.mode === 'workflow', context.userQuery, selectedToolNames);
 | 
					    const prompt = getPrompt('finalRecommendations', context.mode === 'workflow', context.userQuery, selectedToolNames);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    return this.callMicroTaskAI(prompt, context, 350);
 | 
					    const result = await this.callMicroTaskAI(prompt, context, 350, 'final-recommendations');
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if (result.success) {
 | 
				
			||||||
 | 
					      // AUDIT: Final recommendations
 | 
				
			||||||
 | 
					      auditService.addAIDecision(
 | 
				
			||||||
 | 
					        'synthesis',
 | 
				
			||||||
 | 
					        prompt,
 | 
				
			||||||
 | 
					        result.content,
 | 
				
			||||||
 | 
					        85,
 | 
				
			||||||
 | 
					        `Generated final ${context.mode} recommendations`,
 | 
				
			||||||
 | 
					        taskStart,
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          microTaskType: 'final-recommendations',
 | 
				
			||||||
 | 
					          mode: context.mode,
 | 
				
			||||||
 | 
					          selectedToolsCount: selectedToolNames.length,
 | 
				
			||||||
 | 
					          contentLength: result.content.length,
 | 
				
			||||||
 | 
					          ...result.aiUsage
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
  private async completeUnderrepresentedPhases(context: PipelineContext, toolsData: any): Promise<void> {
 | 
					    return result;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private async completeUnderrepresentedPhases(context: PipelineContext, toolsData: any, pipelineStart: number): Promise<void> {
 | 
				
			||||||
    const phases = toolsData.phases || [];
 | 
					    const phases = toolsData.phases || [];
 | 
				
			||||||
    const selectedPhases = new Map<string, number>();
 | 
					    const selectedPhases = new Map<string, number>();
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
@ -382,13 +638,34 @@ class AIPipeline {
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
    console.log('[AI-PIPELINE] Completing underrepresented phases:', underrepresentedPhases.map((p: any) => p.id).join(', '));
 | 
					    console.log('[AI-PIPELINE] Completing underrepresented phases:', underrepresentedPhases.map((p: any) => p.id).join(', '));
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    // AUDIT: Phase completion start
 | 
				
			||||||
 | 
					    auditService.addEntry(
 | 
				
			||||||
 | 
					      'phase-completion',
 | 
				
			||||||
 | 
					      'underrepresented-phases-detected',
 | 
				
			||||||
 | 
					      { 
 | 
				
			||||||
 | 
					        underrepresentedPhases: underrepresentedPhases.map(p => p.id),
 | 
				
			||||||
 | 
					        currentPhaseDistribution: Array.from(selectedPhases.entries())
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      { 
 | 
				
			||||||
 | 
					        phasesToComplete: underrepresentedPhases.length,
 | 
				
			||||||
 | 
					        completionStrategy: 'semantic-search'
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      70,
 | 
				
			||||||
 | 
					      pipelineStart,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        totalPhases: phases.length,
 | 
				
			||||||
 | 
					        adequatelyRepresented: phases.length - underrepresentedPhases.length,
 | 
				
			||||||
 | 
					        completionMethod: 'semantic-phase-search'
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    for (const phase of underrepresentedPhases) {
 | 
					    for (const phase of underrepresentedPhases) {
 | 
				
			||||||
      await this.completePhaseWithSemanticSearch(context, phase, toolsData);
 | 
					      await this.completePhaseWithSemanticSearch(context, phase, toolsData, pipelineStart);
 | 
				
			||||||
      await this.delay(this.config.microTaskDelay);
 | 
					      await this.delay(this.config.microTaskDelay);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async completePhaseWithSemanticSearch(context: PipelineContext, phase: any, toolsData: any): Promise<void> {
 | 
					  private async completePhaseWithSemanticSearch(context: PipelineContext, phase: any, toolsData: any, pipelineStart: number): Promise<void> {
 | 
				
			||||||
    const phaseStart = Date.now();
 | 
					    const phaseStart = Date.now();
 | 
				
			||||||
    const phaseQuery = `forensic ${phase.name.toLowerCase()} tools methods`;
 | 
					    const phaseQuery = `forensic ${phase.name.toLowerCase()} tools methods`;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
@ -397,6 +674,19 @@ class AIPipeline {
 | 
				
			|||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const phaseResults = await embeddingsService.findSimilar(phaseQuery, 20, 0.2);
 | 
					      const phaseResults = await embeddingsService.findSimilar(phaseQuery, 20, 0.2);
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
 | 
					      // AUDIT: Embeddings search for phase completion
 | 
				
			||||||
 | 
					      auditService.addEmbeddingsSearch(
 | 
				
			||||||
 | 
					        phaseQuery,
 | 
				
			||||||
 | 
					        phaseResults,
 | 
				
			||||||
 | 
					        0.2,
 | 
				
			||||||
 | 
					        phaseStart,
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          phaseId: phase.id,
 | 
				
			||||||
 | 
					          phaseName: phase.name,
 | 
				
			||||||
 | 
					          completionPurpose: 'underrepresented-phase-enhancement'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
      if (phaseResults.length === 0) {
 | 
					      if (phaseResults.length === 0) {
 | 
				
			||||||
        console.log('[AI-PIPELINE] No semantic results for phase:', phase.id);
 | 
					        console.log('[AI-PIPELINE] No semantic results for phase:', phase.id);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
@ -422,7 +712,7 @@ class AIPipeline {
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      // Add tools with justification
 | 
					      // Add tools with justification and audit each addition
 | 
				
			||||||
      for (const tool of phaseTools) {
 | 
					      for (const tool of phaseTools) {
 | 
				
			||||||
        const justification = `Nachträglich hinzugefügt zur Vervollständigung der ${phase.name}-Phase. Die ursprüngliche KI-Auswahl war zu spezifisch und hat wichtige Tools für diese Phase übersehen.`;
 | 
					        const justification = `Nachträglich hinzugefügt zur Vervollständigung der ${phase.name}-Phase. Die ursprüngliche KI-Auswahl war zu spezifisch und hat wichtige Tools für diese Phase übersehen.`;
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
@ -436,11 +726,40 @@ class AIPipeline {
 | 
				
			|||||||
          ['Nachträgliche Ergänzung via semantische Phasensuche']
 | 
					          ['Nachträgliche Ergänzung via semantische Phasensuche']
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					        // AUDIT: Phase completion tool addition
 | 
				
			||||||
 | 
					        auditService.addPhaseCompletion(
 | 
				
			||||||
 | 
					          phase.id,
 | 
				
			||||||
 | 
					          [tool.name],
 | 
				
			||||||
 | 
					          justification,
 | 
				
			||||||
 | 
					          phaseStart,
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            toolName: tool.name,
 | 
				
			||||||
 | 
					            toolType: tool.type,
 | 
				
			||||||
 | 
					            semanticSimilarity: phaseResults.find(r => r.name === tool.name)?.similarity,
 | 
				
			||||||
 | 
					            completionReason: 'underrepresented-phase',
 | 
				
			||||||
 | 
					            originalSelectionMissed: true
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        console.log('[AI-PIPELINE] Added phase completion tool:', tool.name);
 | 
					        console.log('[AI-PIPELINE] Added phase completion tool:', tool.name);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
    } catch (error) {
 | 
					    } catch (error) {
 | 
				
			||||||
      console.error('[AI-PIPELINE] Phase completion failed for:', phase.id, error);
 | 
					      console.error('[AI-PIPELINE] Phase completion failed for:', phase.id, error);
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // AUDIT: Phase completion failure
 | 
				
			||||||
 | 
					      auditService.addEntry(
 | 
				
			||||||
 | 
					        'phase-completion',
 | 
				
			||||||
 | 
					        'completion-failed',
 | 
				
			||||||
 | 
					        { phaseId: phase.id, error: error.message },
 | 
				
			||||||
 | 
					        { success: false },
 | 
				
			||||||
 | 
					        20,
 | 
				
			||||||
 | 
					        phaseStart,
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          errorType: error.constructor.name,
 | 
				
			||||||
 | 
					          phaseId: phase.id
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -476,6 +795,18 @@ class AIPipeline {
 | 
				
			|||||||
          st.limitations || []
 | 
					          st.limitations || []
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // AUDIT: Confidence calculation for each tool
 | 
				
			||||||
 | 
					        auditService.addConfidenceCalculation(
 | 
				
			||||||
 | 
					          st.tool.name,
 | 
				
			||||||
 | 
					          confidence,
 | 
				
			||||||
 | 
					          Date.now(),
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            phase: st.phase,
 | 
				
			||||||
 | 
					            priority: st.priority,
 | 
				
			||||||
 | 
					            toolType: st.tool.type
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
          name: st.tool.name,
 | 
					          name: st.tool.name,
 | 
				
			||||||
          type: st.tool.type,
 | 
					          type: st.tool.type,
 | 
				
			||||||
@ -508,6 +839,17 @@ class AIPipeline {
 | 
				
			|||||||
          st.limitations || []
 | 
					          st.limitations || []
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // AUDIT: Confidence calculation for each tool
 | 
				
			||||||
 | 
					        auditService.addConfidenceCalculation(
 | 
				
			||||||
 | 
					          st.tool.name,
 | 
				
			||||||
 | 
					          confidence,
 | 
				
			||||||
 | 
					          Date.now(),
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            rank: st.tool.evaluation?.rank || 1,
 | 
				
			||||||
 | 
					            toolType: st.tool.type
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
          name: st.tool.name,
 | 
					          name: st.tool.name,
 | 
				
			||||||
          type: st.tool.type,
 | 
					          type: st.tool.type,
 | 
				
			||||||
@ -532,7 +874,12 @@ class AIPipeline {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Helper methods
 | 
					  // Helper methods
 | 
				
			||||||
  private async callMicroTaskAI(prompt: string, context: PipelineContext, maxTokens: number = 500): Promise<MicroTaskResult> {
 | 
					  private async callMicroTaskAI(
 | 
				
			||||||
 | 
					    prompt: string, 
 | 
				
			||||||
 | 
					    context: PipelineContext, 
 | 
				
			||||||
 | 
					    maxTokens: number = 500,
 | 
				
			||||||
 | 
					    taskType: string = 'micro-task'
 | 
				
			||||||
 | 
					  ): Promise<MicroTaskResult> {
 | 
				
			||||||
    const startTime = Date.now();
 | 
					    const startTime = Date.now();
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    let contextPrompt = prompt;
 | 
					    let contextPrompt = prompt;
 | 
				
			||||||
@ -549,15 +896,16 @@ class AIPipeline {
 | 
				
			|||||||
      const response = await aiService.callMicroTaskAI(contextPrompt, maxTokens);
 | 
					      const response = await aiService.callMicroTaskAI(contextPrompt, maxTokens);
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      return {
 | 
					      return {
 | 
				
			||||||
        taskType: 'micro-task',
 | 
					        taskType,
 | 
				
			||||||
        content: response.content,
 | 
					        content: response.content,
 | 
				
			||||||
        processingTimeMs: Date.now() - startTime,
 | 
					        processingTimeMs: Date.now() - startTime,
 | 
				
			||||||
        success: true
 | 
					        success: true,
 | 
				
			||||||
 | 
					        aiUsage: response.usage
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    } catch (error) {
 | 
					    } catch (error) {
 | 
				
			||||||
      return {
 | 
					      return {
 | 
				
			||||||
        taskType: 'micro-task',
 | 
					        taskType,
 | 
				
			||||||
        content: '',
 | 
					        content: '',
 | 
				
			||||||
        processingTimeMs: Date.now() - startTime,
 | 
					        processingTimeMs: Date.now() - startTime,
 | 
				
			||||||
        success: false,
 | 
					        success: false,
 | 
				
			||||||
@ -608,48 +956,21 @@ class AIPipeline {
 | 
				
			|||||||
    return 'low';
 | 
					    return 'low';
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private safeParseJSON(jsonString: string, fallback: any = null): any {
 | 
					  private truncateForAudit(text: string, maxLength: number = 200): string {
 | 
				
			||||||
    try {
 | 
					    if (typeof text !== 'string') return String(text);
 | 
				
			||||||
      let cleaned = jsonString.trim();
 | 
					    if (text.length <= maxLength) return text;
 | 
				
			||||||
      
 | 
					    return text.slice(0, maxLength) + '...[audit-truncated]';
 | 
				
			||||||
      // Remove code block markers
 | 
					 | 
				
			||||||
      const jsonBlockPatterns = [
 | 
					 | 
				
			||||||
        /```json\s*([\s\S]*?)\s*```/i,
 | 
					 | 
				
			||||||
        /```\s*([\s\S]*?)\s*```/i,
 | 
					 | 
				
			||||||
        /\{[\s\S]*\}/,
 | 
					 | 
				
			||||||
      ];
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      for (const pattern of jsonBlockPatterns) {
 | 
					 | 
				
			||||||
        const match = cleaned.match(pattern);
 | 
					 | 
				
			||||||
        if (match) {
 | 
					 | 
				
			||||||
          cleaned = match[1] || match[0];
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return JSON.parse(cleaned);
 | 
					  private trackTokenUsage(usage?: { promptTokens?: number; completionTokens?: number; totalTokens?: number }): void {
 | 
				
			||||||
      
 | 
					    if (usage?.totalTokens) {
 | 
				
			||||||
    } catch (error) {
 | 
					      this.totalTokensUsed += usage.totalTokens;
 | 
				
			||||||
      console.warn('[AI-PIPELINE] JSON parsing failed:', error.message);
 | 
					 | 
				
			||||||
      return fallback;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async delay(ms: number): Promise<void> {
 | 
					  private async delay(ms: number): Promise<void> {
 | 
				
			||||||
    return new Promise(resolve => setTimeout(resolve, ms));
 | 
					    return new Promise(resolve => setTimeout(resolve, ms));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  private addAuditEntry(
 | 
					 | 
				
			||||||
    phase: string,
 | 
					 | 
				
			||||||
    action: string,
 | 
					 | 
				
			||||||
    input: any,
 | 
					 | 
				
			||||||
    output: any,
 | 
					 | 
				
			||||||
    confidence: number,
 | 
					 | 
				
			||||||
    startTime: number,
 | 
					 | 
				
			||||||
    metadata: Record<string, any> = {}
 | 
					 | 
				
			||||||
  ): void {
 | 
					 | 
				
			||||||
    auditService.addEntry(phase, action, input, output, confidence, startTime, metadata);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const aiPipeline = new AIPipeline();
 | 
					export const aiPipeline = new AIPipeline();
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
// src/utils/auditService.ts - Refactored
 | 
					// src/utils/auditService.ts - Enhanced for forensic-grade transparency
 | 
				
			||||||
import 'dotenv/config';
 | 
					import 'dotenv/config';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function env(key: string, fallback: string | undefined = undefined): string | undefined {
 | 
					function env(key: string, fallback: string | undefined = undefined): string | undefined {
 | 
				
			||||||
@ -19,7 +19,29 @@ export interface AuditEntry {
 | 
				
			|||||||
  output: any;
 | 
					  output: any;
 | 
				
			||||||
  confidence: number;
 | 
					  confidence: number;
 | 
				
			||||||
  processingTimeMs: number;
 | 
					  processingTimeMs: number;
 | 
				
			||||||
  metadata: Record<string, any>;
 | 
					  metadata: {
 | 
				
			||||||
 | 
					    aiModel?: string;
 | 
				
			||||||
 | 
					    aiParameters?: any;
 | 
				
			||||||
 | 
					    promptTokens?: number;
 | 
				
			||||||
 | 
					    completionTokens?: number;
 | 
				
			||||||
 | 
					    toolsDataHash?: string;
 | 
				
			||||||
 | 
					    embeddingsUsed?: boolean;
 | 
				
			||||||
 | 
					    selectionMethod?: string;
 | 
				
			||||||
 | 
					    microTaskType?: string;
 | 
				
			||||||
 | 
					    confidenceFactors?: string[];
 | 
				
			||||||
 | 
					    reasoning?: string;
 | 
				
			||||||
 | 
					    aiPrompt?: string;
 | 
				
			||||||
 | 
					    aiResponse?: string;
 | 
				
			||||||
 | 
					    toolSelectionCriteria?: string;
 | 
				
			||||||
 | 
					    availableToolsCount?: number;
 | 
				
			||||||
 | 
					    selectedToolsCount?: number;
 | 
				
			||||||
 | 
					    phaseId?: string;
 | 
				
			||||||
 | 
					    toolsAdded?: string[];
 | 
				
			||||||
 | 
					    completionReasoning?: string;
 | 
				
			||||||
 | 
					    similarityScores?: Record<string, number>;
 | 
				
			||||||
 | 
					    contextLength?: number;
 | 
				
			||||||
 | 
					    [key: string]: any;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface AuditConfig {
 | 
					interface AuditConfig {
 | 
				
			||||||
@ -87,6 +109,135 @@ class AuditService {
 | 
				
			|||||||
    console.log(`[AUDIT-SERVICE] ${phase}/${action}: ${confidence}% confidence, ${entry.processingTimeMs}ms`);
 | 
					    console.log(`[AUDIT-SERVICE] ${phase}/${action}: ${confidence}% confidence, ${entry.processingTimeMs}ms`);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // NEW: Specialized audit methods for forensic transparency
 | 
				
			||||||
 | 
					  addAIDecision(
 | 
				
			||||||
 | 
					    phase: string,
 | 
				
			||||||
 | 
					    aiPrompt: string,
 | 
				
			||||||
 | 
					    aiResponse: string,
 | 
				
			||||||
 | 
					    confidence: number,
 | 
				
			||||||
 | 
					    reasoning: string,
 | 
				
			||||||
 | 
					    startTime: number,
 | 
				
			||||||
 | 
					    metadata: Record<string, any> = {}
 | 
				
			||||||
 | 
					  ): void {
 | 
				
			||||||
 | 
					    this.addEntry(
 | 
				
			||||||
 | 
					      phase,
 | 
				
			||||||
 | 
					      'ai-decision',
 | 
				
			||||||
 | 
					      { prompt: this.truncateForAudit(aiPrompt) },
 | 
				
			||||||
 | 
					      { response: this.truncateForAudit(aiResponse) },
 | 
				
			||||||
 | 
					      confidence,
 | 
				
			||||||
 | 
					      startTime,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        ...metadata,
 | 
				
			||||||
 | 
					        reasoning,
 | 
				
			||||||
 | 
					        aiPrompt: this.config.detailLevel === 'verbose' ? aiPrompt : this.truncateForAudit(aiPrompt),
 | 
				
			||||||
 | 
					        aiResponse: this.config.detailLevel === 'verbose' ? aiResponse : this.truncateForAudit(aiResponse)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  addToolSelection(
 | 
				
			||||||
 | 
					    selectedTools: string[],
 | 
				
			||||||
 | 
					    availableTools: string[],
 | 
				
			||||||
 | 
					    selectionMethod: string,
 | 
				
			||||||
 | 
					    confidence: number,
 | 
				
			||||||
 | 
					    startTime: number,
 | 
				
			||||||
 | 
					    metadata: Record<string, any> = {}
 | 
				
			||||||
 | 
					  ): void {
 | 
				
			||||||
 | 
					    this.addEntry(
 | 
				
			||||||
 | 
					      'tool-selection',
 | 
				
			||||||
 | 
					      'selection-decision',
 | 
				
			||||||
 | 
					      { availableTools: availableTools.length > 10 ? availableTools.slice(0, 10) : availableTools },
 | 
				
			||||||
 | 
					      { selectedTools },
 | 
				
			||||||
 | 
					      confidence,
 | 
				
			||||||
 | 
					      startTime,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        ...metadata,
 | 
				
			||||||
 | 
					        selectionMethod,
 | 
				
			||||||
 | 
					        availableToolsCount: availableTools.length,
 | 
				
			||||||
 | 
					        selectedToolsCount: selectedTools.length,
 | 
				
			||||||
 | 
					        toolSelectionCriteria: `${selectionMethod} selection from ${availableTools.length} available tools`
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  addPhaseCompletion(
 | 
				
			||||||
 | 
					    phaseId: string,
 | 
				
			||||||
 | 
					    toolsAdded: string[],
 | 
				
			||||||
 | 
					    completionReasoning: string,
 | 
				
			||||||
 | 
					    startTime: number,
 | 
				
			||||||
 | 
					    metadata: Record<string, any> = {}
 | 
				
			||||||
 | 
					  ): void {
 | 
				
			||||||
 | 
					    this.addEntry(
 | 
				
			||||||
 | 
					      'phase-completion',
 | 
				
			||||||
 | 
					      'phase-enhancement',
 | 
				
			||||||
 | 
					      { phaseId, underrepresentedPhase: true },
 | 
				
			||||||
 | 
					      { toolsAdded },
 | 
				
			||||||
 | 
					      75, // Default confidence for phase completion
 | 
				
			||||||
 | 
					      startTime,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        ...metadata,
 | 
				
			||||||
 | 
					        phaseId,
 | 
				
			||||||
 | 
					        toolsAdded,
 | 
				
			||||||
 | 
					        completionReasoning,
 | 
				
			||||||
 | 
					        enhancementType: 'semantic-phase-completion'
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  addEmbeddingsSearch(
 | 
				
			||||||
 | 
					    query: string,
 | 
				
			||||||
 | 
					    similarResults: any[],
 | 
				
			||||||
 | 
					    threshold: number,
 | 
				
			||||||
 | 
					    startTime: number,
 | 
				
			||||||
 | 
					    metadata: Record<string, any> = {}
 | 
				
			||||||
 | 
					  ): void {
 | 
				
			||||||
 | 
					    const similarityScores = similarResults.reduce((acc, result) => {
 | 
				
			||||||
 | 
					      acc[result.name] = result.similarity;
 | 
				
			||||||
 | 
					      return acc;
 | 
				
			||||||
 | 
					    }, {} as Record<string, number>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.addEntry(
 | 
				
			||||||
 | 
					      'embeddings',
 | 
				
			||||||
 | 
					      'similarity-search',
 | 
				
			||||||
 | 
					      { query: this.truncateForAudit(query), threshold },
 | 
				
			||||||
 | 
					      { resultsCount: similarResults.length, topResults: similarResults.slice(0, 5).map(r => r.name) },
 | 
				
			||||||
 | 
					      similarResults.length > 0 ? 85 : 50,
 | 
				
			||||||
 | 
					      startTime,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        ...metadata,
 | 
				
			||||||
 | 
					        embeddingsUsed: true,
 | 
				
			||||||
 | 
					        similarityScores,
 | 
				
			||||||
 | 
					        searchThreshold: threshold,
 | 
				
			||||||
 | 
					        totalMatches: similarResults.length
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  addConfidenceCalculation(
 | 
				
			||||||
 | 
					    toolName: string,
 | 
				
			||||||
 | 
					    confidenceBreakdown: any,
 | 
				
			||||||
 | 
					    startTime: number,
 | 
				
			||||||
 | 
					    metadata: Record<string, any> = {}
 | 
				
			||||||
 | 
					  ): void {
 | 
				
			||||||
 | 
					    this.addEntry(
 | 
				
			||||||
 | 
					      'confidence-scoring',
 | 
				
			||||||
 | 
					      'tool-confidence',
 | 
				
			||||||
 | 
					      { toolName },
 | 
				
			||||||
 | 
					      { confidenceBreakdown },
 | 
				
			||||||
 | 
					      confidenceBreakdown.overall || 50,
 | 
				
			||||||
 | 
					      startTime,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        ...metadata,
 | 
				
			||||||
 | 
					        confidenceFactors: [
 | 
				
			||||||
 | 
					          ...(confidenceBreakdown.strengthIndicators || []),
 | 
				
			||||||
 | 
					          ...(confidenceBreakdown.uncertaintyFactors || [])
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        semanticRelevance: confidenceBreakdown.semanticRelevance,
 | 
				
			||||||
 | 
					        taskSuitability: confidenceBreakdown.taskSuitability
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getCurrentAuditTrail(): AuditEntry[] {
 | 
					  getCurrentAuditTrail(): AuditEntry[] {
 | 
				
			||||||
    return [...this.activeAuditTrail];
 | 
					    return [...this.activeAuditTrail];
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -135,6 +286,12 @@ class AuditService {
 | 
				
			|||||||
    return data;
 | 
					    return data;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private truncateForAudit(text: string, maxLength: number = 300): string {
 | 
				
			||||||
 | 
					    if (typeof text !== 'string') return String(text);
 | 
				
			||||||
 | 
					    if (text.length <= maxLength) return text;
 | 
				
			||||||
 | 
					    return text.slice(0, maxLength) + '...[truncated for audit]';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  isEnabled(): boolean {
 | 
					  isEnabled(): boolean {
 | 
				
			||||||
    return this.config.enabled;
 | 
					    return this.config.enabled;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -143,7 +300,7 @@ class AuditService {
 | 
				
			|||||||
    return { ...this.config };
 | 
					    return { ...this.config };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Statistics and analysis methods
 | 
					  // Statistics and analysis methods (enhanced)
 | 
				
			||||||
  getAuditStatistics(auditTrail: AuditEntry[]): {
 | 
					  getAuditStatistics(auditTrail: AuditEntry[]): {
 | 
				
			||||||
    totalTime: number;
 | 
					    totalTime: number;
 | 
				
			||||||
    avgConfidence: number;
 | 
					    avgConfidence: number;
 | 
				
			||||||
@ -151,6 +308,14 @@ class AuditService {
 | 
				
			|||||||
    highConfidenceSteps: number;
 | 
					    highConfidenceSteps: number;
 | 
				
			||||||
    lowConfidenceSteps: number;
 | 
					    lowConfidenceSteps: number;
 | 
				
			||||||
    phaseBreakdown: Record<string, { count: number; avgConfidence: number; totalTime: number }>;
 | 
					    phaseBreakdown: Record<string, { count: number; avgConfidence: number; totalTime: number }>;
 | 
				
			||||||
 | 
					    aiDecisionCount: number;
 | 
				
			||||||
 | 
					    embeddingsUsageCount: number;
 | 
				
			||||||
 | 
					    toolSelectionCount: number;
 | 
				
			||||||
 | 
					    qualityMetrics: {
 | 
				
			||||||
 | 
					      avgProcessingTime: number;
 | 
				
			||||||
 | 
					      confidenceDistribution: { high: number; medium: number; low: number };
 | 
				
			||||||
 | 
					      aiTransparency: number;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
  } {
 | 
					  } {
 | 
				
			||||||
    if (!auditTrail || auditTrail.length === 0) {
 | 
					    if (!auditTrail || auditTrail.length === 0) {
 | 
				
			||||||
      return {
 | 
					      return {
 | 
				
			||||||
@ -159,7 +324,15 @@ class AuditService {
 | 
				
			|||||||
        stepCount: 0,
 | 
					        stepCount: 0,
 | 
				
			||||||
        highConfidenceSteps: 0,
 | 
					        highConfidenceSteps: 0,
 | 
				
			||||||
        lowConfidenceSteps: 0,
 | 
					        lowConfidenceSteps: 0,
 | 
				
			||||||
        phaseBreakdown: {}
 | 
					        phaseBreakdown: {},
 | 
				
			||||||
 | 
					        aiDecisionCount: 0,
 | 
				
			||||||
 | 
					        embeddingsUsageCount: 0,
 | 
				
			||||||
 | 
					        toolSelectionCount: 0,
 | 
				
			||||||
 | 
					        qualityMetrics: {
 | 
				
			||||||
 | 
					          avgProcessingTime: 0,
 | 
				
			||||||
 | 
					          confidenceDistribution: { high: 0, medium: 0, low: 0 },
 | 
				
			||||||
 | 
					          aiTransparency: 0
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -171,6 +344,12 @@ class AuditService {
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
    const highConfidenceSteps = auditTrail.filter(entry => (entry.confidence || 0) >= 80).length;
 | 
					    const highConfidenceSteps = auditTrail.filter(entry => (entry.confidence || 0) >= 80).length;
 | 
				
			||||||
    const lowConfidenceSteps = auditTrail.filter(entry => (entry.confidence || 0) < 60).length;
 | 
					    const lowConfidenceSteps = auditTrail.filter(entry => (entry.confidence || 0) < 60).length;
 | 
				
			||||||
 | 
					    const mediumConfidenceSteps = auditTrail.length - highConfidenceSteps - lowConfidenceSteps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Enhanced metrics
 | 
				
			||||||
 | 
					    const aiDecisionCount = auditTrail.filter(entry => entry.action === 'ai-decision').length;
 | 
				
			||||||
 | 
					    const embeddingsUsageCount = auditTrail.filter(entry => entry.metadata?.embeddingsUsed).length;
 | 
				
			||||||
 | 
					    const toolSelectionCount = auditTrail.filter(entry => entry.action === 'selection-decision').length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Phase breakdown
 | 
					    // Phase breakdown
 | 
				
			||||||
    const phaseBreakdown: Record<string, { count: number; avgConfidence: number; totalTime: number }> = {};
 | 
					    const phaseBreakdown: Record<string, { count: number; avgConfidence: number; totalTime: number }> = {};
 | 
				
			||||||
@ -197,13 +376,29 @@ class AuditService {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const avgProcessingTime = auditTrail.length > 0 ? totalTime / auditTrail.length : 0;
 | 
				
			||||||
 | 
					    const aiTransparency = auditTrail.length > 0 ? 
 | 
				
			||||||
 | 
					      (auditTrail.filter(entry => entry.metadata?.aiPrompt || entry.metadata?.reasoning).length / auditTrail.length) * 100 : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      totalTime,
 | 
					      totalTime,
 | 
				
			||||||
      avgConfidence,
 | 
					      avgConfidence,
 | 
				
			||||||
      stepCount: auditTrail.length,
 | 
					      stepCount: auditTrail.length,
 | 
				
			||||||
      highConfidenceSteps,
 | 
					      highConfidenceSteps,
 | 
				
			||||||
      lowConfidenceSteps,
 | 
					      lowConfidenceSteps,
 | 
				
			||||||
      phaseBreakdown
 | 
					      phaseBreakdown,
 | 
				
			||||||
 | 
					      aiDecisionCount,
 | 
				
			||||||
 | 
					      embeddingsUsageCount,
 | 
				
			||||||
 | 
					      toolSelectionCount,
 | 
				
			||||||
 | 
					      qualityMetrics: {
 | 
				
			||||||
 | 
					        avgProcessingTime,
 | 
				
			||||||
 | 
					        confidenceDistribution: { 
 | 
				
			||||||
 | 
					          high: highConfidenceSteps, 
 | 
				
			||||||
 | 
					          medium: mediumConfidenceSteps, 
 | 
				
			||||||
 | 
					          low: lowConfidenceSteps 
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        aiTransparency: Math.round(aiTransparency)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -238,6 +433,15 @@ class AuditService {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Enhanced validation for audit quality
 | 
				
			||||||
 | 
					      if (entry.action === 'ai-decision' && !entry.metadata?.aiPrompt && !entry.metadata?.reasoning) {
 | 
				
			||||||
 | 
					        warnings.push(`Entry ${index}: AI decision lacks transparency (no prompt or reasoning)`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (entry.action === 'selection-decision' && !entry.metadata?.selectionMethod) {
 | 
				
			||||||
 | 
					        warnings.push(`Entry ${index}: Tool selection lacks methodology info`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Data type validation
 | 
					      // Data type validation
 | 
				
			||||||
      if (typeof entry.confidence !== 'number' || entry.confidence < 0 || entry.confidence > 100) {
 | 
					      if (typeof entry.confidence !== 'number' || entry.confidence < 0 || entry.confidence > 100) {
 | 
				
			||||||
        warnings.push(`Entry ${index} has invalid confidence value: ${entry.confidence}`);
 | 
					        warnings.push(`Entry ${index} has invalid confidence value: ${entry.confidence}`);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
// src/utils/confidenceScoring.ts
 | 
					// src/utils/confidenceScoring.ts
 | 
				
			||||||
import { isToolHosted } from './toolHelpers.js';
 | 
					import { isToolHosted } from './clientUtils.js';
 | 
				
			||||||
import 'dotenv/config';
 | 
					import 'dotenv/config';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ConfidenceMetrics {
 | 
					export interface ConfidenceMetrics {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
// src/utils/jsonUtils.ts
 | 
					// src/utils/jsonUtils.ts - Centralized JSON parsing and utilities
 | 
				
			||||||
export class JSONParser {
 | 
					export class JSONParser {
 | 
				
			||||||
  static safeParseJSON(jsonString: string, fallback: any = null): any {
 | 
					  static safeParseJSON(jsonString: string, fallback: any = null): any {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
@ -129,4 +129,246 @@ export class JSONParser {
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
    return { selectedTools, selectedConcepts };
 | 
					    return { selectedTools, selectedConcepts };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static secureParseJSON(jsonString: string, maxSize: number = 10 * 1024 * 1024): any {
 | 
				
			||||||
 | 
					    if (typeof jsonString !== 'string') {
 | 
				
			||||||
 | 
					      throw new Error('Input must be a string');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (jsonString.length > maxSize) {
 | 
				
			||||||
 | 
					      throw new Error(`JSON string too large (${jsonString.length} bytes, max ${maxSize})`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Security checks for potentially malicious content
 | 
				
			||||||
 | 
					    const suspiciousPatterns = [
 | 
				
			||||||
 | 
					      /<script/i,
 | 
				
			||||||
 | 
					      /javascript:/i,
 | 
				
			||||||
 | 
					      /eval\(/i,
 | 
				
			||||||
 | 
					      /function\s*\(/i,
 | 
				
			||||||
 | 
					      /__proto__/i,
 | 
				
			||||||
 | 
					      /constructor/i
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (const pattern of suspiciousPatterns) {
 | 
				
			||||||
 | 
					      if (pattern.test(jsonString)) {
 | 
				
			||||||
 | 
					        throw new Error('Potentially malicious content detected in JSON');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const parsed = JSON.parse(jsonString);
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // Validate basic structure
 | 
				
			||||||
 | 
					      if (typeof parsed !== 'object' || parsed === null) {
 | 
				
			||||||
 | 
					        throw new Error('JSON must be an object');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return parsed;
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					      if (error instanceof SyntaxError) {
 | 
				
			||||||
 | 
					        throw new Error(`Invalid JSON syntax: ${error.message}`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      throw error;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static sanitizeForAudit(obj: any, maxDepth: number = 5, currentDepth: number = 0): any {
 | 
				
			||||||
 | 
					    if (currentDepth >= maxDepth) {
 | 
				
			||||||
 | 
					      return '[Max depth reached]';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (obj === null || obj === undefined) {
 | 
				
			||||||
 | 
					      return obj;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (typeof obj === 'string') {
 | 
				
			||||||
 | 
					      // Sanitize strings that might contain sensitive data
 | 
				
			||||||
 | 
					      if (obj.length > 500) {
 | 
				
			||||||
 | 
					        return obj.slice(0, 500) + '...[truncated]';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // Remove potential code injection patterns
 | 
				
			||||||
 | 
					      return obj.replace(/<script[\s\S]*?<\/script>/gi, '[script removed]');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (typeof obj === 'number' || typeof obj === 'boolean') {
 | 
				
			||||||
 | 
					      return obj;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (Array.isArray(obj)) {
 | 
				
			||||||
 | 
					      if (obj.length > 20) {
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					          ...obj.slice(0, 20).map(item => this.sanitizeForAudit(item, maxDepth, currentDepth + 1)),
 | 
				
			||||||
 | 
					          `...[${obj.length - 20} more items]`
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return obj.map(item => this.sanitizeForAudit(item, maxDepth, currentDepth + 1));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (typeof obj === 'object') {
 | 
				
			||||||
 | 
					      const keys = Object.keys(obj);
 | 
				
			||||||
 | 
					      if (keys.length > 50) {
 | 
				
			||||||
 | 
					        const sanitized: any = {};
 | 
				
			||||||
 | 
					        keys.slice(0, 50).forEach(key => {
 | 
				
			||||||
 | 
					          sanitized[key] = this.sanitizeForAudit(obj[key], maxDepth, currentDepth + 1);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        sanitized['[truncated]'] = `${keys.length - 50} more properties`;
 | 
				
			||||||
 | 
					        return sanitized;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const sanitized: any = {};
 | 
				
			||||||
 | 
					      keys.forEach(key => {
 | 
				
			||||||
 | 
					        // Skip potential dangerous properties
 | 
				
			||||||
 | 
					        if (['__proto__', 'constructor', 'prototype'].includes(key)) {
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        sanitized[key] = this.sanitizeForAudit(obj[key], maxDepth, currentDepth + 1);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      return sanitized;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return String(obj);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static validateAuditExportStructure(data: any): { isValid: boolean; errors: string[] } {
 | 
				
			||||||
 | 
					    const errors: string[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!data || typeof data !== 'object') {
 | 
				
			||||||
 | 
					      errors.push('Export data must be an object');
 | 
				
			||||||
 | 
					      return { isValid: false, errors };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check required top-level properties
 | 
				
			||||||
 | 
					    const requiredProps = ['metadata', 'recommendation', 'auditTrail'];
 | 
				
			||||||
 | 
					    for (const prop of requiredProps) {
 | 
				
			||||||
 | 
					      if (!(prop in data)) {
 | 
				
			||||||
 | 
					        errors.push(`Missing required property: ${prop}`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Validate metadata
 | 
				
			||||||
 | 
					    if (data.metadata && typeof data.metadata === 'object') {
 | 
				
			||||||
 | 
					      const requiredMetadataProps = ['timestamp', 'version', 'userQuery', 'mode'];
 | 
				
			||||||
 | 
					      for (const prop of requiredMetadataProps) {
 | 
				
			||||||
 | 
					        if (!(prop in data.metadata)) {
 | 
				
			||||||
 | 
					          errors.push(`Missing required metadata property: ${prop}`);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      errors.push('Invalid metadata structure');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Validate audit trail
 | 
				
			||||||
 | 
					    if (!Array.isArray(data.auditTrail)) {
 | 
				
			||||||
 | 
					      errors.push('auditTrail must be an array');
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      data.auditTrail.forEach((entry: any, index: number) => {
 | 
				
			||||||
 | 
					        if (!entry || typeof entry !== 'object') {
 | 
				
			||||||
 | 
					          errors.push(`Audit entry ${index} is not a valid object`);
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const requiredEntryProps = ['timestamp', 'phase', 'action', 'confidence', 'processingTimeMs'];
 | 
				
			||||||
 | 
					        for (const prop of requiredEntryProps) {
 | 
				
			||||||
 | 
					          if (!(prop in entry)) {
 | 
				
			||||||
 | 
					            errors.push(`Audit entry ${index} missing required property: ${prop}`);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      isValid: errors.length === 0,
 | 
				
			||||||
 | 
					      errors
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static prepareAuditExport(
 | 
				
			||||||
 | 
					    recommendation: any,
 | 
				
			||||||
 | 
					    userQuery: string,
 | 
				
			||||||
 | 
					    mode: string,
 | 
				
			||||||
 | 
					    auditTrail: any[] = [],
 | 
				
			||||||
 | 
					    additionalMetadata: any = {}
 | 
				
			||||||
 | 
					  ): any {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      metadata: {
 | 
				
			||||||
 | 
					        timestamp: new Date().toISOString(),
 | 
				
			||||||
 | 
					        version: "1.0",
 | 
				
			||||||
 | 
					        userQuery: userQuery.slice(0, 1000), // Truncate for security
 | 
				
			||||||
 | 
					        mode,
 | 
				
			||||||
 | 
					        exportedBy: 'ForensicPathways',
 | 
				
			||||||
 | 
					        toolsDataHash: additionalMetadata.toolsDataHash || 'unknown',
 | 
				
			||||||
 | 
					        aiModel: additionalMetadata.aiModel || 'unknown',
 | 
				
			||||||
 | 
					        aiParameters: additionalMetadata.aiParameters || {},
 | 
				
			||||||
 | 
					        processingStats: additionalMetadata.processingStats || {}
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      recommendation: this.sanitizeForAudit(recommendation, 6),
 | 
				
			||||||
 | 
					      auditTrail: auditTrail.map(entry => this.sanitizeForAudit(entry, 4)),
 | 
				
			||||||
 | 
					      rawContext: {
 | 
				
			||||||
 | 
					        selectedTools: additionalMetadata.selectedTools || [],
 | 
				
			||||||
 | 
					        backgroundKnowledge: additionalMetadata.backgroundKnowledge || [],
 | 
				
			||||||
 | 
					        contextHistory: additionalMetadata.contextHistory || [],
 | 
				
			||||||
 | 
					        embeddingsSimilarities: additionalMetadata.embeddingsSimilarities || {}
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static validateUploadedAnalysis(data: any): { isValid: boolean; issues: string[]; warnings: string[] } {
 | 
				
			||||||
 | 
					    const issues: string[] = [];
 | 
				
			||||||
 | 
					    const warnings: string[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Basic structure validation
 | 
				
			||||||
 | 
					    const structureValidation = this.validateAuditExportStructure(data);
 | 
				
			||||||
 | 
					    if (!structureValidation.isValid) {
 | 
				
			||||||
 | 
					      issues.push(...structureValidation.errors);
 | 
				
			||||||
 | 
					      return { isValid: false, issues, warnings };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Additional validation for uploaded content
 | 
				
			||||||
 | 
					    if (data.metadata) {
 | 
				
			||||||
 | 
					      // Check timestamp validity
 | 
				
			||||||
 | 
					      const timestamp = new Date(data.metadata.timestamp);
 | 
				
			||||||
 | 
					      if (isNaN(timestamp.getTime())) {
 | 
				
			||||||
 | 
					        warnings.push('Invalid timestamp in metadata');
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        const age = Date.now() - timestamp.getTime();
 | 
				
			||||||
 | 
					        const maxAge = 30 * 24 * 60 * 60 * 1000; // 30 days
 | 
				
			||||||
 | 
					        if (age > maxAge) {
 | 
				
			||||||
 | 
					          warnings.push(`Analysis is ${Math.floor(age / (24 * 60 * 60 * 1000))} days old`);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Validate mode
 | 
				
			||||||
 | 
					      if (!['workflow', 'tool'].includes(data.metadata.mode)) {
 | 
				
			||||||
 | 
					        warnings.push(`Unknown analysis mode: ${data.metadata.mode}`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Validate audit trail quality
 | 
				
			||||||
 | 
					    if (Array.isArray(data.auditTrail)) {
 | 
				
			||||||
 | 
					      const aiDecisions = data.auditTrail.filter(e => e.action === 'ai-decision').length;
 | 
				
			||||||
 | 
					      const toolSelections = data.auditTrail.filter(e => e.action === 'selection-decision').length;
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      if (aiDecisions === 0) {
 | 
				
			||||||
 | 
					        warnings.push('No AI decisions found in audit trail');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      if (toolSelections === 0) {
 | 
				
			||||||
 | 
					        warnings.push('No tool selections found in audit trail');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Check for confidence values
 | 
				
			||||||
 | 
					      const entriesWithConfidence = data.auditTrail.filter(e => typeof e.confidence === 'number').length;
 | 
				
			||||||
 | 
					      const confidenceRatio = entriesWithConfidence / data.auditTrail.length;
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      if (confidenceRatio < 0.8) {
 | 
				
			||||||
 | 
					        warnings.push(`Only ${Math.round(confidenceRatio * 100)}% of audit entries have confidence scores`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      isValid: issues.length === 0,
 | 
				
			||||||
 | 
					      issues,
 | 
				
			||||||
 | 
					      warnings
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1,22 +0,0 @@
 | 
				
			|||||||
// src/utils/toolHelpers.ts
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface Tool {
 | 
					 | 
				
			||||||
  name: string;
 | 
					 | 
				
			||||||
  type?: 'software' | 'method' | 'concept';
 | 
					 | 
				
			||||||
  projectUrl?: string | null;
 | 
					 | 
				
			||||||
  license?: string;
 | 
					 | 
				
			||||||
  knowledgebase?: boolean;
 | 
					 | 
				
			||||||
  domains?: string[];
 | 
					 | 
				
			||||||
  phases?: string[];
 | 
					 | 
				
			||||||
  platforms?: string[];
 | 
					 | 
				
			||||||
  skillLevel?: string;
 | 
					 | 
				
			||||||
  description?: string;
 | 
					 | 
				
			||||||
  tags?: string[];
 | 
					 | 
				
			||||||
  related_concepts?: string[];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export { 
 | 
					 | 
				
			||||||
  createToolSlug, 
 | 
					 | 
				
			||||||
  findToolByIdentifier, 
 | 
					 | 
				
			||||||
  isToolHosted 
 | 
					 | 
				
			||||||
} from './clientUtils.js';
 | 
					 | 
				
			||||||
@ -2,6 +2,7 @@
 | 
				
			|||||||
import { aiService } from './aiService.js';
 | 
					import { aiService } from './aiService.js';
 | 
				
			||||||
import { embeddingsService, type SimilarityResult } from './embeddings.js';
 | 
					import { embeddingsService, type SimilarityResult } from './embeddings.js';
 | 
				
			||||||
import { confidenceScoring } from './confidenceScoring.js';
 | 
					import { confidenceScoring } from './confidenceScoring.js';
 | 
				
			||||||
 | 
					import { JSONParser } from './jsonUtils.js'; // FIXED: Use centralized JSON parsing
 | 
				
			||||||
import { getPrompt } from '../config/prompts.js';
 | 
					import { getPrompt } from '../config/prompts.js';
 | 
				
			||||||
import 'dotenv/config';
 | 
					import 'dotenv/config';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -248,7 +249,8 @@ class ToolSelector {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const response = await aiService.callAI(prompt, { maxTokens: 2500 });
 | 
					      const response = await aiService.callAI(prompt, { maxTokens: 2500 });
 | 
				
			||||||
      const result = this.safeParseJSON(response.content, null);
 | 
					      // FIXED: Use centralized JSON parsing
 | 
				
			||||||
 | 
					      const result = JSONParser.safeParseJSON(response.content, null);
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      if (!result || !Array.isArray(result.selectedTools) || !Array.isArray(result.selectedConcepts)) {
 | 
					      if (!result || !Array.isArray(result.selectedTools) || !Array.isArray(result.selectedConcepts)) {
 | 
				
			||||||
        console.error('[TOOL-SELECTOR] AI selection returned invalid structure');
 | 
					        console.error('[TOOL-SELECTOR] AI selection returned invalid structure');
 | 
				
			||||||
@ -313,7 +315,8 @@ class ToolSelector {
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const response = await aiService.callMicroTaskAI(prompt, 1000);
 | 
					      const response = await aiService.callMicroTaskAI(prompt, 1000);
 | 
				
			||||||
      const selections = this.safeParseJSON(response.content, []);
 | 
					      // FIXED: Use centralized JSON parsing
 | 
				
			||||||
 | 
					      const selections = JSONParser.safeParseJSON(response.content, []);
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      if (Array.isArray(selections)) {
 | 
					      if (Array.isArray(selections)) {
 | 
				
			||||||
        const validSelections = selections.filter((sel: any) => {
 | 
					        const validSelections = selections.filter((sel: any) => {
 | 
				
			||||||
@ -365,90 +368,7 @@ class ToolSelector {
 | 
				
			|||||||
    related_software: concept.related_software || []
 | 
					    related_software: concept.related_software || []
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private safeParseJSON(jsonString: string, fallback: any = null): any {
 | 
					  // REMOVED: safeParseJSON method - now using centralized version from jsonUtils.ts
 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      let cleaned = jsonString.trim();
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      // Remove code block markers
 | 
					 | 
				
			||||||
      const jsonBlockPatterns = [
 | 
					 | 
				
			||||||
        /```json\s*([\s\S]*?)\s*```/i,
 | 
					 | 
				
			||||||
        /```\s*([\s\S]*?)\s*```/i,
 | 
					 | 
				
			||||||
        /\{[\s\S]*\}/,
 | 
					 | 
				
			||||||
      ];
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      for (const pattern of jsonBlockPatterns) {
 | 
					 | 
				
			||||||
        const match = cleaned.match(pattern);
 | 
					 | 
				
			||||||
        if (match) {
 | 
					 | 
				
			||||||
          cleaned = match[1] || match[0];
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      // Handle truncated JSON
 | 
					 | 
				
			||||||
      if (!cleaned.endsWith('}') && !cleaned.endsWith(']')) {
 | 
					 | 
				
			||||||
        console.warn('[TOOL-SELECTOR] JSON appears truncated, attempting recovery');
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        let braceCount = 0;
 | 
					 | 
				
			||||||
        let bracketCount = 0;
 | 
					 | 
				
			||||||
        let inString = false;
 | 
					 | 
				
			||||||
        let escaped = false;
 | 
					 | 
				
			||||||
        let lastCompleteStructure = '';
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        for (let i = 0; i < cleaned.length; i++) {
 | 
					 | 
				
			||||||
          const char = cleaned[i];
 | 
					 | 
				
			||||||
          
 | 
					 | 
				
			||||||
          if (escaped) {
 | 
					 | 
				
			||||||
            escaped = false;
 | 
					 | 
				
			||||||
            continue;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          
 | 
					 | 
				
			||||||
          if (char === '\\') {
 | 
					 | 
				
			||||||
            escaped = true;
 | 
					 | 
				
			||||||
            continue;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          
 | 
					 | 
				
			||||||
          if (char === '"' && !escaped) {
 | 
					 | 
				
			||||||
            inString = !inString;
 | 
					 | 
				
			||||||
            continue;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          
 | 
					 | 
				
			||||||
          if (!inString) {
 | 
					 | 
				
			||||||
            if (char === '{') braceCount++;
 | 
					 | 
				
			||||||
            if (char === '}') braceCount--;
 | 
					 | 
				
			||||||
            if (char === '[') bracketCount++;
 | 
					 | 
				
			||||||
            if (char === ']') bracketCount--;
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            if (braceCount === 0 && bracketCount === 0 && (char === '}' || char === ']')) {
 | 
					 | 
				
			||||||
              lastCompleteStructure = cleaned.substring(0, i + 1);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        if (lastCompleteStructure) {
 | 
					 | 
				
			||||||
          cleaned = lastCompleteStructure;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          if (braceCount > 0) cleaned += '}';
 | 
					 | 
				
			||||||
          if (bracketCount > 0) cleaned += ']';
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      const parsed = JSON.parse(cleaned);
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      // Ensure proper structure
 | 
					 | 
				
			||||||
      if (parsed && typeof parsed === 'object') {
 | 
					 | 
				
			||||||
        if (!parsed.selectedTools) parsed.selectedTools = [];
 | 
					 | 
				
			||||||
        if (!parsed.selectedConcepts) parsed.selectedConcepts = [];
 | 
					 | 
				
			||||||
        if (!Array.isArray(parsed.selectedTools)) parsed.selectedTools = [];
 | 
					 | 
				
			||||||
        if (!Array.isArray(parsed.selectedConcepts)) parsed.selectedConcepts = [];
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      return parsed;
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
    } catch (error) {
 | 
					 | 
				
			||||||
      console.warn('[TOOL-SELECTOR] JSON parsing failed:', error.message);
 | 
					 | 
				
			||||||
      return fallback;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getConfig(): ToolSelectionConfig {
 | 
					  getConfig(): ToolSelectionConfig {
 | 
				
			||||||
    return { ...this.config };
 | 
					    return { ...this.config };
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user