// src/utils/aiPipeline.ts - FIXED: Critical error corrections import { getCompressedToolsDataForAI } from './dataService.js'; import { embeddingsService, type EmbeddingData } from './embeddings.js'; interface AIConfig { endpoint: string; apiKey: string; model: string; } interface MicroTaskResult { taskType: string; content: string; processingTimeMs: number; success: boolean; error?: string; } interface AnalysisResult { recommendation: any; processingStats: { embeddingsUsed: boolean; candidatesFromEmbeddings: number; finalSelectedItems: number; processingTimeMs: number; microTasksCompleted: number; microTasksFailed: number; contextContinuityUsed: boolean; }; } interface AnalysisContext { userQuery: string; mode: string; filteredData: any; contextHistory: string[]; // FIXED: Add max context length tracking maxContextLength: number; currentContextLength: number; scenarioAnalysis?: string; problemAnalysis?: string; investigationApproach?: string; criticalConsiderations?: string; selectedTools?: Array<{tool: any, phase: string, priority: string, justification?: string}>; backgroundKnowledge?: Array<{concept: any, relevance: string}>; // FIXED: Add seen tools tracking to prevent duplicates seenToolNames: Set; } class ImprovedMicroTaskAIPipeline { private config: AIConfig; private maxSelectedItems: number; private embeddingCandidates: number; private similarityThreshold: number; private microTaskDelay: number; // FIXED: Add proper token management private maxContextTokens: number; private maxPromptTokens: number; constructor() { this.config = { endpoint: this.getEnv('AI_ANALYZER_ENDPOINT'), apiKey: this.getEnv('AI_ANALYZER_API_KEY'), model: this.getEnv('AI_ANALYZER_MODEL') }; this.maxSelectedItems = parseInt(process.env.AI_MAX_SELECTED_ITEMS || '60', 10); this.embeddingCandidates = parseInt(process.env.AI_EMBEDDING_CANDIDATES || '60', 10); this.similarityThreshold = 0.3; this.microTaskDelay = parseInt(process.env.AI_MICRO_TASK_DELAY_MS || '500', 10); // FIXED: Token management this.maxContextTokens = parseInt(process.env.AI_MAX_CONTEXT_TOKENS || '4000', 10); this.maxPromptTokens = parseInt(process.env.AI_MAX_PROMPT_TOKENS || '1500', 10); } private getEnv(key: string): string { const value = process.env[key]; if (!value) { throw new Error(`Missing environment variable: ${key}`); } return value; } // FIXED: Estimate token count (rough approximation) private estimateTokens(text: string): number { return Math.ceil(text.length / 4); // Rough estimate: 4 chars per token } // FIXED: Manage context history with token limits private addToContextHistory(context: AnalysisContext, newEntry: string): void { const entryTokens = this.estimateTokens(newEntry); // Add new entry context.contextHistory.push(newEntry); context.currentContextLength += entryTokens; // Prune old entries if exceeding limits while (context.currentContextLength > this.maxContextTokens && context.contextHistory.length > 1) { const removed = context.contextHistory.shift()!; context.currentContextLength -= this.estimateTokens(removed); } } // FIXED: Safe JSON parsing with validation private safeParseJSON(jsonString: string, fallback: any = null): any { try { const cleaned = jsonString .replace(/^```json\s*/i, '') .replace(/\s*```\s*$/g, '') .trim(); const parsed = JSON.parse(cleaned); return parsed; } catch (error) { console.warn('[AI PIPELINE] JSON parsing failed:', error.message); console.warn('[AI PIPELINE] Raw content:', jsonString.slice(0, 200)); return fallback; } } // FIXED: Add tool deduplication private addToolToSelection(context: AnalysisContext, tool: any, phase: string, priority: string, justification?: string): boolean { if (context.seenToolNames.has(tool.name)) { console.log(`[AI PIPELINE] Skipping duplicate tool: ${tool.name}`); return false; } context.seenToolNames.add(tool.name); if (!context.selectedTools) context.selectedTools = []; context.selectedTools.push({ tool, phase, priority, justification }); return true; } private async getIntelligentCandidates(userQuery: string, toolsData: any, mode: string) { let candidateTools: any[] = []; let candidateConcepts: any[] = []; let selectionMethod = 'unknown'; if (embeddingsService.isEnabled()) { const similarItems = await embeddingsService.findSimilar( userQuery, this.embeddingCandidates, this.similarityThreshold ); const toolNames = new Set(); const conceptNames = new Set(); similarItems.forEach(item => { if (item.type === 'tool') toolNames.add(item.name); if (item.type === 'concept') conceptNames.add(item.name); }); console.log(`[IMPROVED PIPELINE] Embeddings found: ${toolNames.size} tools, ${conceptNames.size} concepts`); // FIXED: Use your expected flow - get full data of embeddings results if (toolNames.size >= 15) { // Reasonable threshold for quality candidateTools = toolsData.tools.filter((tool: any) => toolNames.has(tool.name)); candidateConcepts = toolsData.concepts.filter((concept: any) => conceptNames.has(concept.name)); selectionMethod = 'embeddings_candidates'; console.log(`[IMPROVED PIPELINE] Using embeddings candidates: ${candidateTools.length} tools`); } else { console.log(`[IMPROVED PIPELINE] Embeddings insufficient (${toolNames.size} < 15), using full dataset`); candidateTools = toolsData.tools; candidateConcepts = toolsData.concepts; selectionMethod = 'full_dataset'; } } else { console.log(`[IMPROVED PIPELINE] Embeddings disabled, using full dataset`); candidateTools = toolsData.tools; candidateConcepts = toolsData.concepts; selectionMethod = 'full_dataset'; } // FIXED: NOW AI ANALYZES FULL DATA of the candidates console.log(`[IMPROVED PIPELINE] AI will analyze FULL DATA of ${candidateTools.length} candidate tools`); const finalSelection = await this.aiSelectionWithFullData(userQuery, candidateTools, candidateConcepts, mode, selectionMethod); return { tools: finalSelection.selectedTools, concepts: finalSelection.selectedConcepts, domains: toolsData.domains, phases: toolsData.phases, 'domain-agnostic-software': toolsData['domain-agnostic-software'] }; } // src/utils/aiPipeline.ts - FIXED: De-biased AI selection prompt private async aiSelectionWithFullData( userQuery: string, candidateTools: any[], candidateConcepts: any[], mode: string, selectionMethod: string ) { const modeInstruction = mode === 'workflow' ? 'The user wants a COMPREHENSIVE WORKFLOW with multiple tools/methods across different phases. Select 15-25 tools that cover the full investigation lifecycle.' : 'The user wants SPECIFIC TOOLS/METHODS that directly solve their particular problem. Select 3-8 tools that are most relevant and effective.'; // FIXED: Give AI the COMPLETE tool data, not truncated const toolsWithFullData = candidateTools.map((tool: any) => ({ name: tool.name, type: tool.type, description: tool.description, domains: tool.domains, phases: tool.phases, platforms: tool.platforms || [], tags: tool.tags || [], skillLevel: tool.skillLevel, license: tool.license, accessType: tool.accessType, projectUrl: tool.projectUrl, knowledgebase: tool.knowledgebase, related_concepts: tool.related_concepts || [], related_software: tool.related_software || [] })); const conceptsWithFullData = candidateConcepts.map((concept: any) => ({ name: concept.name, type: 'concept', description: concept.description, domains: concept.domains, phases: concept.phases, tags: concept.tags || [], skillLevel: concept.skillLevel, related_concepts: concept.related_concepts || [], related_software: concept.related_software || [] })); const prompt = `You are a DFIR expert with access to the complete forensics tool database. You need to select the most relevant tools and concepts for this specific query. SELECTION METHOD: ${selectionMethod} ${selectionMethod === 'embeddings_candidates' ? 'These tools were pre-filtered by vector similarity, so they are already relevant. Your job is to select the BEST ones from this relevant set.' : 'You have access to the full tool database. Select the most relevant tools for the query.'} ${modeInstruction} USER QUERY: "${userQuery}" CRITICAL SELECTION PRINCIPLES: 1. **CONTEXT OVER POPULARITY**: Don't default to "famous" tools like Volatility, Wireshark, or Autopsy just because they're well-known. Choose based on SPECIFIC scenario needs. 2. **METHODOLOGY vs SOFTWARE**: - For RAPID/URGENT scenarios → Prioritize METHODS and rapid response approaches - For TIME-CRITICAL incidents → Choose triage methods over deep analysis tools - For COMPREHENSIVE analysis → Then consider detailed software tools - METHODS (type: "method") are often better than SOFTWARE for procedural guidance 3. **SCENARIO-SPECIFIC LOGIC**: - "Rapid/Quick/Urgent/Triage" scenarios → Rapid Incident Response and Triage METHOD > Volatility - "Industrial/SCADA/ICS" scenarios → Specialized ICS tools > generic network tools - "Mobile/Android/iOS" scenarios → Mobile-specific tools > desktop forensics tools - "Memory analysis needed urgently" → Quick memory tools/methods > comprehensive Volatility analysis 4. **AVOID TOOL BIAS**: - Volatility is NOT always the answer for memory analysis - Wireshark is NOT always the answer for network analysis - Autopsy is NOT always the answer for disk analysis - Consider lighter, faster, more appropriate alternatives AVAILABLE TOOLS (with complete data): ${JSON.stringify(toolsWithFullData.slice(0, 30), null, 2)} AVAILABLE CONCEPTS (with complete data): ${JSON.stringify(conceptsWithFullData.slice(0, 10), null, 2)} ANALYSIS INSTRUCTIONS: 1. Read the FULL description of each tool/concept 2. Consider ALL tags, platforms, related tools, and metadata 3. **MATCH URGENCY LEVEL**: Rapid scenarios need rapid methods, not deep analysis tools 4. **MATCH SPECIFICITY**: Specialized scenarios need specialized tools, not generic ones 5. **CONSIDER TYPE**: Methods provide procedural guidance, software provides technical capability 6. For SCADA/ICS queries: prioritize specialized ICS tools over generic network tools 7. For mobile queries: prioritize mobile-specific tools over desktop tools 8. For rapid/urgent queries: prioritize methodology and triage approaches BIAS PREVENTION: - If query mentions "rapid", "quick", "urgent", "triage" → Strongly favor METHODS over deep analysis SOFTWARE - If query mentions specific technologies (SCADA, Android, etc.) → Strongly favor specialized tools - Don't recommend Volatility unless deep memory analysis is specifically needed AND time allows - Don't recommend generic tools when specialized ones are available - Consider the SKILL LEVEL and TIME CONSTRAINTS implied by the query Select the most relevant items (max ${this.maxSelectedItems} total). Respond with ONLY this JSON format: { "selectedTools": ["Tool Name 1", "Tool Name 2", ...], "selectedConcepts": ["Concept Name 1", "Concept Name 2", ...], "reasoning": "Detailed explanation of why these specific tools were selected for this query, addressing why certain popular tools were NOT selected if they were inappropriate for the scenario context" }`; try { const response = await this.callAI(prompt, 2500); // More tokens for bias prevention logic const result = this.safeParseJSON(response, null); if (!result || !Array.isArray(result.selectedTools) || !Array.isArray(result.selectedConcepts)) { console.error('[IMPROVED PIPELINE] AI selection returned invalid structure:', response.slice(0, 200)); throw new Error('AI selection failed to return valid tool selection'); } const totalSelected = result.selectedTools.length + result.selectedConcepts.length; if (totalSelected === 0) { console.error('[IMPROVED PIPELINE] AI selection returned no tools'); throw new Error('AI selection returned empty selection'); } console.log(`[IMPROVED PIPELINE] AI selected: ${result.selectedTools.length} tools, ${result.selectedConcepts.length} concepts`); console.log(`[IMPROVED PIPELINE] AI reasoning: ${result.reasoning}`); // Return the actual tool/concept objects const selectedTools = candidateTools.filter(tool => result.selectedTools.includes(tool.name)); const selectedConcepts = candidateConcepts.filter(concept => result.selectedConcepts.includes(concept.name)); console.log(`[IMPROVED PIPELINE] Final selection: ${selectedTools.length} tools with bias prevention applied`); return { selectedTools, selectedConcepts }; } catch (error) { console.error('[IMPROVED PIPELINE] AI selection failed:', error); // Emergency fallback with bias awareness console.log('[IMPROVED PIPELINE] Using emergency keyword-based selection'); return this.emergencyKeywordSelection(userQuery, candidateTools, candidateConcepts, mode); } } private emergencyKeywordSelection(userQuery: string, candidateTools: any[], candidateConcepts: any[], mode: string) { const queryLower = userQuery.toLowerCase(); const keywords = queryLower.split(/\s+/).filter(word => word.length > 3); // Score tools based on keyword matches in full data const scoredTools = candidateTools.map(tool => { const toolText = ( tool.name + ' ' + tool.description + ' ' + (tool.tags || []).join(' ') + ' ' + (tool.platforms || []).join(' ') + ' ' + (tool.domains || []).join(' ') ).toLowerCase(); const score = keywords.reduce((acc, keyword) => { return acc + (toolText.includes(keyword) ? 1 : 0); }, 0); return { tool, score }; }).filter(item => item.score > 0) .sort((a, b) => b.score - a.score); const maxTools = mode === 'workflow' ? 20 : 8; const selectedTools = scoredTools.slice(0, maxTools).map(item => item.tool); console.log(`[IMPROVED PIPELINE] Emergency selection: ${selectedTools.length} tools, keywords: ${keywords.slice(0, 5).join(', ')}`); return { selectedTools, selectedConcepts: candidateConcepts.slice(0, 3) }; } private async delay(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } private async callMicroTaskAI(prompt: string, context: AnalysisContext, maxTokens: number = 300): Promise { const startTime = Date.now(); // FIXED: Build context prompt with token management let contextPrompt = prompt; if (context.contextHistory.length > 0) { const contextSection = `BISHERIGE ANALYSE:\n${context.contextHistory.join('\n\n')}\n\nAKTUELLE AUFGABE:\n`; const combinedPrompt = contextSection + prompt; // Check if combined prompt exceeds limits if (this.estimateTokens(combinedPrompt) <= this.maxPromptTokens) { contextPrompt = combinedPrompt; } else { console.warn('[AI PIPELINE] Context too long, using prompt only'); // Could implement smarter context truncation here } } try { const response = await this.callAI(contextPrompt, maxTokens); return { taskType: 'micro-task', content: response.trim(), processingTimeMs: Date.now() - startTime, success: true }; } catch (error) { return { taskType: 'micro-task', content: '', processingTimeMs: Date.now() - startTime, success: false, error: error.message }; } } private async analyzeScenario(context: AnalysisContext): Promise { const isWorkflow = context.mode === 'workflow'; const prompt = `Sie sind ein erfahrener DFIR-Experte. Analysieren Sie das folgende ${isWorkflow ? 'forensische Szenario' : 'technische Problem'}. ${isWorkflow ? 'FORENSISCHES SZENARIO' : 'TECHNISCHES PROBLEM'}: "${context.userQuery}" Führen Sie eine systematische ${isWorkflow ? 'Szenario-Analyse' : 'Problem-Analyse'} durch und berücksichtigen Sie dabei: ${isWorkflow ? `- Angriffsvektoren und Bedrohungsmodellierung nach MITRE ATT&CK - Betroffene Systeme und kritische Infrastrukturen - Zeitkritische Faktoren und Beweiserhaltung - Forensische Artefakte und Datenquellen` : `- Spezifische forensische Herausforderungen - Verfügbare Datenquellen und deren Integrität - Methodische Anforderungen für rechtssichere Analyse` } WICHTIG: Antworten Sie NUR in fließendem deutschen Text ohne Listen, Aufzählungen oder Markdown-Formatierung. Maximum 150 Wörter.`; const result = await this.callMicroTaskAI(prompt, context, 220); if (result.success) { if (isWorkflow) { context.scenarioAnalysis = result.content; } else { context.problemAnalysis = result.content; } // FIXED: Use new context management this.addToContextHistory(context, `${isWorkflow ? 'Szenario' : 'Problem'}-Analyse: ${result.content.slice(0, 200)}...`); } return result; } private async generateApproach(context: AnalysisContext): Promise { const isWorkflow = context.mode === 'workflow'; const prompt = `Basierend auf der Analyse entwickeln Sie einen fundierten ${isWorkflow ? 'Untersuchungsansatz' : 'Lösungsansatz'} nach NIST SP 800-86 Methodik. ${isWorkflow ? 'SZENARIO' : 'PROBLEM'}: "${context.userQuery}" Entwickeln Sie einen systematischen ${isWorkflow ? 'Untersuchungsansatz' : 'Lösungsansatz'} unter Berücksichtigung von: ${isWorkflow ? `- Triage-Prioritäten nach forensischer Dringlichkeit - Phasenabfolge nach NIST-Methodik - Kontaminationsvermeidung und forensische Isolierung` : `- Methodik-Auswahl nach wissenschaftlichen Kriterien - Validierung und Verifizierung der gewählten Ansätze - Integration in bestehende forensische Workflows` } WICHTIG: Antworten Sie NUR in fließendem deutschen Text ohne Listen oder Markdown. Maximum 150 Wörter.`; const result = await this.callMicroTaskAI(prompt, context, 220); if (result.success) { context.investigationApproach = result.content; this.addToContextHistory(context, `${isWorkflow ? 'Untersuchungs' : 'Lösungs'}ansatz: ${result.content.slice(0, 200)}...`); } return result; } private async generateCriticalConsiderations(context: AnalysisContext): Promise { const isWorkflow = context.mode === 'workflow'; const prompt = `Identifizieren Sie ${isWorkflow ? 'kritische forensische Überlegungen' : 'wichtige methodische Voraussetzungen'} für diesen Fall. ${isWorkflow ? 'SZENARIO' : 'PROBLEM'}: "${context.userQuery}" Berücksichtigen Sie folgende forensische Aspekte: ${isWorkflow ? `- Time-sensitive evidence preservation - Chain of custody requirements und rechtliche Verwertbarkeit - Incident containment vs. evidence preservation Dilemma - Privacy- und Compliance-Anforderungen` : `- Tool-Validierung und Nachvollziehbarkeit - False positive/negative Risiken bei der gewählten Methodik - Qualifikationsanforderungen für die Durchführung - Dokumentations- und Reporting-Standards` } WICHTIG: Antworten Sie NUR in fließendem deutschen Text ohne Listen oder Markdown. Maximum 120 Wörter.`; const result = await this.callMicroTaskAI(prompt, context, 180); if (result.success) { context.criticalConsiderations = result.content; this.addToContextHistory(context, `Kritische Überlegungen: ${result.content.slice(0, 200)}...`); } return result; } private async selectToolsForPhase(context: AnalysisContext, phase: any): Promise { const phaseTools = context.filteredData.tools.filter((tool: any) => tool.phases && tool.phases.includes(phase.id) ); if (phaseTools.length === 0) { return { taskType: 'tool-selection', content: JSON.stringify([]), processingTimeMs: 0, success: true }; } const prompt = `Wählen Sie 2-3 Methoden/Tools für die Phase "${phase.name}" basierend auf objektiven, fallbezogenen Kriterien. SZENARIO: "${context.userQuery}" VERFÜGBARE TOOLS FÜR ${phase.name.toUpperCase()}: ${phaseTools.map((tool: any) => `- ${tool.name}: ${tool.description.slice(0, 100)}...`).join('\n')} Wählen Sie Methoden/Tools nach forensischen Kriterien aus: - Court admissibility und Chain of Custody Kompatibilität - Integration in forensische Standard-Workflows - Reproduzierbarkeit und Dokumentationsqualität - Objektivität Antworten Sie AUSSCHLIESSLICH mit diesem JSON-Format (kein zusätzlicher Text): [ { "toolName": "Exakter Methoden/Tool-Name", "priority": "high|medium|low", "justification": "Objektive Begründung warum diese Methode/Tool für das spezifische Szenario besser geeignet ist" } ]`; const result = await this.callMicroTaskAI(prompt, context, 450); if (result.success) { // FIXED: Safe JSON parsing with validation const selections = this.safeParseJSON(result.content, []); if (Array.isArray(selections)) { const validSelections = selections.filter((sel: any) => sel.toolName && phaseTools.some((tool: any) => tool.name === sel.toolName) ); validSelections.forEach((sel: any) => { const tool = phaseTools.find((t: any) => t.name === sel.toolName); if (tool) { // FIXED: Use deduplication helper this.addToolToSelection(context, tool, phase.id, sel.priority, sel.justification); } }); } } return result; } private async evaluateSpecificTool(context: AnalysisContext, tool: any, rank: number): Promise { const prompt = `Bewerten Sie diese Methode/Tool fallbezogen für das spezifische Problem nach forensischen Qualitätskriterien. PROBLEM: "${context.userQuery}" TOOL: ${tool.name} BESCHREIBUNG: ${tool.description} PLATTFORMEN: ${tool.platforms?.join(', ') || 'N/A'} SKILL LEVEL: ${tool.skillLevel} Bewerten Sie nach forensischen Standards und antworten Sie AUSSCHLIESSLICH mit diesem JSON-Format: { "suitability_score": "high|medium|low", "detailed_explanation": "Detaillierte forensische Begründung warum diese Methode/Tool das Problem löst", "implementation_approach": "Konkrete methodische Schritte zur korrekten Anwendung für dieses spezifische Problem", "pros": ["Forensischer Vorteil 1", "Validierter Vorteil 2"], "cons": ["Methodische Limitation 1", "Potenzielle Schwäche 2"], "alternatives": "Alternative Ansätze falls diese Methode/Tool nicht optimal ist" }`; const result = await this.callMicroTaskAI(prompt, context, 650); if (result.success) { // FIXED: Safe JSON parsing const evaluation = this.safeParseJSON(result.content, { suitability_score: 'medium', detailed_explanation: 'Evaluation failed', implementation_approach: '', pros: [], cons: [], alternatives: '' }); // FIXED: Use deduplication helper this.addToolToSelection(context, { ...tool, evaluation: { ...evaluation, rank } }, 'evaluation', evaluation.suitability_score); } return result; } private async selectBackgroundKnowledge(context: AnalysisContext): Promise { const availableConcepts = context.filteredData.concepts; if (availableConcepts.length === 0) { return { taskType: 'background-knowledge', content: JSON.stringify([]), processingTimeMs: 0, success: true }; } const selectedToolNames = context.selectedTools?.map(st => st.tool.name) || []; const prompt = `Wählen Sie relevante forensische Konzepte für das Verständnis der empfohlenen Methodik. ${context.mode === 'workflow' ? 'SZENARIO' : 'PROBLEM'}: "${context.userQuery}" EMPFOHLENE TOOLS: ${selectedToolNames.join(', ')} VERFÜGBARE KONZEPTE: ${availableConcepts.slice(0, 15).map((concept: any) => `- ${concept.name}: ${concept.description.slice(0, 80)}...`).join('\n')} Wählen Sie 2-4 Konzepte aus, die für das Verständnis der forensischen Methodik essentiell sind. Antworten Sie AUSSCHLIESSLICH mit diesem JSON-Format: [ { "conceptName": "Exakter Konzept-Name", "relevance": "Forensische Relevanz: Warum dieses Konzept für das Verständnis der Methodik kritisch ist" } ]`; const result = await this.callMicroTaskAI(prompt, context, 400); if (result.success) { // FIXED: Safe JSON parsing const selections = this.safeParseJSON(result.content, []); if (Array.isArray(selections)) { context.backgroundKnowledge = selections.filter((sel: any) => sel.conceptName && availableConcepts.some((concept: any) => concept.name === sel.conceptName) ).map((sel: any) => ({ concept: availableConcepts.find((c: any) => c.name === sel.conceptName), relevance: sel.relevance })); } } return result; } private async generateFinalRecommendations(context: AnalysisContext): Promise { const isWorkflow = context.mode === 'workflow'; const prompt = isWorkflow ? `Erstellen Sie eine forensisch fundierte Workflow-Empfehlung basierend auf DFIR-Prinzipien. SZENARIO: "${context.userQuery}" AUSGEWÄHLTE TOOLS: ${context.selectedTools?.map(st => st.tool.name).join(', ') || 'Keine Tools ausgewählt'} Erstellen Sie konkrete methodische Workflow-Schritte für dieses spezifische Szenario unter Berücksichtigung forensischer Best Practices, Objektivität und rechtlicher Verwertbarkeit. WICHTIG: Antworten Sie NUR in fließendem deutschen Text ohne Listen oder Markdown. Maximum 120 Wörter.` : `Erstellen Sie wichtige methodische Überlegungen für die korrekte Methoden-/Tool-Anwendung. PROBLEM: "${context.userQuery}" EMPFOHLENE TOOLS: ${context.selectedTools?.map(st => st.tool.name).join(', ') || 'Keine Methoden/Tools ausgewählt'} Geben Sie kritische methodische Überlegungen, Validierungsanforderungen und Qualitätssicherungsmaßnahmen für die korrekte Anwendung der empfohlenen Methoden/Tools. WICHTIG: Antworten Sie NUR in fließendem deutschen Text ohne Listen oder Markdown. Maximum 100 Wörter.`; const result = await this.callMicroTaskAI(prompt, context, 180); return result; } private async callAI(prompt: string, maxTokens: number = 1000): Promise { const response = await fetch(`${this.config.endpoint}/v1/chat/completions`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.config.apiKey}` }, body: JSON.stringify({ model: this.config.model, messages: [{ role: 'user', content: prompt }], max_tokens: maxTokens, temperature: 0.3 }) }); if (!response.ok) { const errorText = await response.text(); throw new Error(`AI API error: ${response.status} - ${errorText}`); } const data = await response.json(); const content = data.choices?.[0]?.message?.content; if (!content) { throw new Error('No response from AI model'); } return content; } async processQuery(userQuery: string, mode: string): Promise { const startTime = Date.now(); let completedTasks = 0; let failedTasks = 0; console.log(`[IMPROVED PIPELINE] Starting ${mode} query processing with context continuity`); try { // Stage 1: Get intelligent candidates (embeddings + AI selection) const toolsData = await getCompressedToolsDataForAI(); const filteredData = await this.getIntelligentCandidates(userQuery, toolsData, mode); // FIXED: Initialize context with proper state management const context: AnalysisContext = { userQuery, mode, filteredData, contextHistory: [], maxContextLength: this.maxContextTokens, currentContextLength: 0, seenToolNames: new Set() // FIXED: Add deduplication tracking }; console.log(`[IMPROVED PIPELINE] Starting micro-tasks with ${filteredData.tools.length} tools visible`); // MICRO-TASK SEQUENCE // Task 1: Scenario/Problem Analysis const analysisResult = await this.analyzeScenario(context); if (analysisResult.success) completedTasks++; else failedTasks++; await this.delay(this.microTaskDelay); // Task 2: Investigation/Solution Approach const approachResult = await this.generateApproach(context); if (approachResult.success) completedTasks++; else failedTasks++; await this.delay(this.microTaskDelay); // Task 3: Critical Considerations const considerationsResult = await this.generateCriticalConsiderations(context); if (considerationsResult.success) completedTasks++; else failedTasks++; await this.delay(this.microTaskDelay); // Task 4: Tool Selection/Evaluation (mode-dependent) if (mode === 'workflow') { // Select tools for each phase const phases = toolsData.phases || []; for (const phase of phases) { const toolSelectionResult = await this.selectToolsForPhase(context, phase); if (toolSelectionResult.success) completedTasks++; else failedTasks++; await this.delay(this.microTaskDelay); } } else { // Evaluate top 3 tools for specific problem const topTools = filteredData.tools.slice(0, 3); for (let i = 0; i < topTools.length; i++) { const evaluationResult = await this.evaluateSpecificTool(context, topTools[i], i + 1); if (evaluationResult.success) completedTasks++; else failedTasks++; await this.delay(this.microTaskDelay); } } // Task 5: Background Knowledge Selection const knowledgeResult = await this.selectBackgroundKnowledge(context); if (knowledgeResult.success) completedTasks++; else failedTasks++; await this.delay(this.microTaskDelay); // Task 6: Final Recommendations const finalResult = await this.generateFinalRecommendations(context); if (finalResult.success) completedTasks++; else failedTasks++; // Build final recommendation const recommendation = this.buildRecommendation(context, mode, finalResult.content); const processingStats = { embeddingsUsed: embeddingsService.isEnabled(), candidatesFromEmbeddings: filteredData.tools.length, finalSelectedItems: (context.selectedTools?.length || 0) + (context.backgroundKnowledge?.length || 0), processingTimeMs: Date.now() - startTime, microTasksCompleted: completedTasks, microTasksFailed: failedTasks, contextContinuityUsed: true }; console.log(`[IMPROVED PIPELINE] Completed: ${completedTasks} tasks, Failed: ${failedTasks} tasks`); console.log(`[IMPROVED PIPELINE] Unique tools selected: ${context.seenToolNames.size}`); return { recommendation, processingStats }; } catch (error) { console.error('[IMPROVED PIPELINE] Processing failed:', error); throw error; } } // Build recommendation (same structure but using fixed context) private buildRecommendation(context: AnalysisContext, mode: string, finalContent: string): any { const isWorkflow = mode === 'workflow'; const base = { [isWorkflow ? 'scenario_analysis' : 'problem_analysis']: isWorkflow ? context.scenarioAnalysis : context.problemAnalysis, investigation_approach: context.investigationApproach, critical_considerations: context.criticalConsiderations, background_knowledge: context.backgroundKnowledge?.map(bk => ({ concept_name: bk.concept.name, relevance: bk.relevance })) || [] }; if (isWorkflow) { return { ...base, recommended_tools: context.selectedTools?.map(st => ({ name: st.tool.name, phase: st.phase, priority: st.priority, justification: st.justification || `Empfohlen für ${st.phase}` })) || [], workflow_suggestion: finalContent }; } else { return { ...base, recommended_tools: context.selectedTools?.map(st => ({ name: st.tool.name, rank: st.tool.evaluation?.rank || 1, suitability_score: st.priority, detailed_explanation: st.tool.evaluation?.detailed_explanation || '', implementation_approach: st.tool.evaluation?.implementation_approach || '', pros: st.tool.evaluation?.pros || [], cons: st.tool.evaluation?.cons || [], alternatives: st.tool.evaluation?.alternatives || '' })) || [], additional_considerations: finalContent }; } } } // Global instance const aiPipeline = new ImprovedMicroTaskAIPipeline(); export { aiPipeline, type AnalysisResult };