phase 2
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
// src/utils/aiPipeline.ts - Refactored
|
||||
import { getCompressedToolsDataForAI } from './dataService.js';
|
||||
// src/utils/aiPipeline.ts - Enhanced with comprehensive audit logging
|
||||
import { getCompressedToolsDataForAI, getDataVersion } from './dataService.js';
|
||||
import { aiService } from './aiService.js';
|
||||
import { toolSelector, type SelectionContext } from './toolSelector.js';
|
||||
import { confidenceScoring, type AnalysisContext } from './confidenceScoring.js';
|
||||
import { embeddingsService } from './embeddings.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 'dotenv/config';
|
||||
|
||||
@@ -20,6 +21,11 @@ interface MicroTaskResult {
|
||||
processingTimeMs: number;
|
||||
success: boolean;
|
||||
error?: string;
|
||||
aiUsage?: {
|
||||
promptTokens?: number;
|
||||
completionTokens?: number;
|
||||
totalTokens?: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface AnalysisResult {
|
||||
@@ -32,6 +38,8 @@ interface AnalysisResult {
|
||||
microTasksCompleted: number;
|
||||
microTasksFailed: number;
|
||||
contextContinuityUsed: boolean;
|
||||
totalAITokensUsed: number;
|
||||
auditEntriesGenerated: number;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -64,6 +72,7 @@ interface PipelineContext {
|
||||
|
||||
class AIPipeline {
|
||||
private config: PipelineConfig;
|
||||
private totalTokensUsed: number = 0;
|
||||
|
||||
constructor() {
|
||||
this.config = {
|
||||
@@ -79,6 +88,7 @@ class AIPipeline {
|
||||
const startTime = Date.now();
|
||||
let completedTasks = 0;
|
||||
let failedTasks = 0;
|
||||
this.totalTokensUsed = 0;
|
||||
|
||||
console.log('[AI-PIPELINE] Starting', mode, 'analysis pipeline');
|
||||
|
||||
@@ -87,6 +97,8 @@ class AIPipeline {
|
||||
|
||||
try {
|
||||
const toolsData = await getCompressedToolsDataForAI();
|
||||
const aiConfig = aiService.getConfig();
|
||||
const toolsDataHash = getDataVersion?.() || 'unknown';
|
||||
|
||||
const context: PipelineContext = {
|
||||
userQuery,
|
||||
@@ -99,67 +111,119 @@ class AIPipeline {
|
||||
embeddingsSimilarities: new Map<string, number>()
|
||||
};
|
||||
|
||||
// Phase 1: Get intelligent tool candidates
|
||||
console.log('[AI-PIPELINE] Phase 1: Tool candidate selection');
|
||||
const candidateData = await toolSelector.getIntelligentCandidates(userQuery, toolsData, mode, context);
|
||||
|
||||
context.filteredData = candidateData;
|
||||
|
||||
this.addAuditEntry(
|
||||
// AUDIT: Pipeline initialization
|
||||
auditService.addEntry(
|
||||
'initialization',
|
||||
'pipeline-start',
|
||||
{ userQuery, mode, toolsDataLoaded: !!toolsData },
|
||||
{ candidateTools: candidateData.tools.length, candidateConcepts: candidateData.concepts.length },
|
||||
{
|
||||
userQuery: this.truncateForAudit(userQuery),
|
||||
mode,
|
||||
toolsDataLoaded: !!toolsData,
|
||||
aiConfig: { model: aiConfig.model }
|
||||
},
|
||||
{
|
||||
totalAvailableTools: toolsData.tools.length,
|
||||
totalAvailableConcepts: toolsData.concepts.length,
|
||||
embeddingsEnabled: embeddingsService.isEnabled()
|
||||
},
|
||||
90,
|
||||
startTime,
|
||||
{ selectionMethod: candidateData.selectionMethod }
|
||||
{
|
||||
toolsDataHash,
|
||||
aiModel: aiConfig.model,
|
||||
embeddingsUsed: embeddingsService.isEnabled(),
|
||||
pipelineVersion: '2.0-enhanced'
|
||||
}
|
||||
);
|
||||
|
||||
// Phase 2: Contextual analysis micro-tasks
|
||||
// Phase 1: Get intelligent tool candidates with enhanced logging
|
||||
console.log('[AI-PIPELINE] Phase 1: Tool candidate selection');
|
||||
const candidateSelectionStart = Date.now();
|
||||
|
||||
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;
|
||||
|
||||
// Phase 2: Contextual analysis micro-tasks with enhanced logging
|
||||
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++;
|
||||
this.trackTokenUsage(analysisResult.aiUsage);
|
||||
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++;
|
||||
this.trackTokenUsage(approachResult.aiUsage);
|
||||
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++;
|
||||
this.trackTokenUsage(considerationsResult.aiUsage);
|
||||
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');
|
||||
|
||||
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 {
|
||||
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');
|
||||
|
||||
const knowledgeResult = await this.selectBackgroundKnowledge(context);
|
||||
const knowledgeResult = await this.selectBackgroundKnowledge(context, startTime);
|
||||
if (knowledgeResult.success) completedTasks++; else failedTasks++;
|
||||
this.trackTokenUsage(knowledgeResult.aiUsage);
|
||||
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++;
|
||||
this.trackTokenUsage(finalResult.aiUsage);
|
||||
|
||||
// Build final recommendation
|
||||
const recommendation = this.buildRecommendation(context, mode, finalResult.content);
|
||||
|
||||
this.addAuditEntry(
|
||||
// AUDIT: Pipeline completion
|
||||
auditService.addEntry(
|
||||
'completion',
|
||||
'pipeline-end',
|
||||
{ completedTasks, failedTasks },
|
||||
{ finalRecommendation: !!recommendation, auditEntriesGenerated: auditService.getCurrentAuditTrail().length },
|
||||
{ completedTasks, failedTasks, totalTokensUsed: this.totalTokensUsed },
|
||||
{
|
||||
finalRecommendation: !!recommendation,
|
||||
auditEntriesGenerated: auditService.getCurrentAuditTrail().length,
|
||||
selectedToolsCount: context.selectedTools?.length || 0,
|
||||
backgroundKnowledgeCount: context.backgroundKnowledge?.length || 0
|
||||
},
|
||||
completedTasks > failedTasks ? 85 : 60,
|
||||
startTime,
|
||||
{ totalProcessingTimeMs: Date.now() - startTime }
|
||||
{
|
||||
totalProcessingTimeMs: Date.now() - startTime,
|
||||
aiModel: aiConfig.model,
|
||||
finalTokenUsage: this.totalTokensUsed,
|
||||
pipelineEfficiency: completedTasks / (completedTasks + failedTasks)
|
||||
}
|
||||
);
|
||||
|
||||
const processingStats = {
|
||||
@@ -169,7 +233,9 @@ class AIPipeline {
|
||||
processingTimeMs: Date.now() - startTime,
|
||||
microTasksCompleted: completedTasks,
|
||||
microTasksFailed: failedTasks,
|
||||
contextContinuityUsed: true
|
||||
contextContinuityUsed: true,
|
||||
totalAITokensUsed: this.totalTokensUsed,
|
||||
auditEntriesGenerated: auditService.getCurrentAuditTrail().length
|
||||
};
|
||||
|
||||
console.log('[AI-PIPELINE] Pipeline completed successfully:', {
|
||||
@@ -177,7 +243,9 @@ class AIPipeline {
|
||||
processingTimeMs: processingStats.processingTimeMs,
|
||||
completedTasks,
|
||||
failedTasks,
|
||||
finalItems: processingStats.finalSelectedItems
|
||||
finalItems: processingStats.finalSelectedItems,
|
||||
totalTokensUsed: this.totalTokensUsed,
|
||||
auditEntries: processingStats.auditEntriesGenerated
|
||||
});
|
||||
|
||||
// Finalize audit trail
|
||||
@@ -193,6 +261,18 @@ class AIPipeline {
|
||||
|
||||
} catch (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;
|
||||
}
|
||||
}
|
||||
@@ -201,23 +281,63 @@ class AIPipeline {
|
||||
context: PipelineContext,
|
||||
toolsData: any,
|
||||
completedTasks: number,
|
||||
failedTasks: number
|
||||
): Promise<void> {
|
||||
failedTasks: number,
|
||||
pipelineStart: number
|
||||
): Promise<{ completed: number; failed: number }> {
|
||||
const phases = toolsData.phases || [];
|
||||
|
||||
// Select tools for each phase
|
||||
// Select tools for each phase with enhanced logging
|
||||
for (const phase of phases) {
|
||||
const phaseStart = Date.now();
|
||||
const phaseTools = context.filteredData.tools.filter((tool: any) =>
|
||||
tool && tool.phases && Array.isArray(tool.phases) && tool.phases.includes(phase.id)
|
||||
);
|
||||
|
||||
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) => {
|
||||
const tool = phaseTools.find((t: any) => t && t.name === sel.toolName);
|
||||
if (tool) {
|
||||
const priority = this.derivePriorityFromScore(sel.taskRelevance);
|
||||
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);
|
||||
}
|
||||
|
||||
// Complete underrepresented phases
|
||||
await this.completeUnderrepresentedPhases(context, toolsData);
|
||||
// Complete underrepresented phases with enhanced logging
|
||||
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);
|
||||
|
||||
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++;
|
||||
this.trackTokenUsage(evaluationResult.aiUsage);
|
||||
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');
|
||||
const taskStart = Date.now();
|
||||
const isWorkflow = context.mode === 'workflow';
|
||||
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 (isWorkflow) {
|
||||
@@ -254,52 +385,109 @@ class AIPipeline {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private async generateApproach(context: PipelineContext): Promise<MicroTaskResult> {
|
||||
private async generateApproach(context: PipelineContext, pipelineStart: number): Promise<MicroTaskResult> {
|
||||
console.log('[AI-PIPELINE] Micro-task: Investigation approach');
|
||||
const taskStart = Date.now();
|
||||
const isWorkflow = context.mode === 'workflow';
|
||||
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) {
|
||||
context.investigationApproach = result.content;
|
||||
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;
|
||||
}
|
||||
|
||||
private async generateCriticalConsiderations(context: PipelineContext): Promise<MicroTaskResult> {
|
||||
private async generateCriticalConsiderations(context: PipelineContext, pipelineStart: number): Promise<MicroTaskResult> {
|
||||
console.log('[AI-PIPELINE] Micro-task: Critical considerations');
|
||||
const taskStart = Date.now();
|
||||
const isWorkflow = context.mode === 'workflow';
|
||||
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) {
|
||||
context.criticalConsiderations = result.content;
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
const taskStart = Date.now();
|
||||
const existingSelection = context.selectedTools?.find((st: any) => st.tool && st.tool.name === tool.name);
|
||||
const taskRelevance = existingSelection?.taskRelevance || 70;
|
||||
const priority = this.derivePriorityFromScore(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) {
|
||||
const evaluation = this.safeParseJSON(result.content, {
|
||||
// FIXED: Use centralized JSON parsing
|
||||
const evaluation = JSONParser.safeParseJSON(result.content, {
|
||||
detailed_explanation: 'Evaluation failed',
|
||||
implementation_approach: '',
|
||||
pros: [],
|
||||
@@ -315,13 +503,35 @@ class AIPipeline {
|
||||
task_relevance: taskRelevance
|
||||
}
|
||||
}, '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;
|
||||
}
|
||||
|
||||
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');
|
||||
const taskStart = Date.now();
|
||||
const availableConcepts = context.filteredData.concepts;
|
||||
|
||||
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 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) {
|
||||
const selections = this.safeParseJSON(result.content, []);
|
||||
// FIXED: Use centralized JSON parsing
|
||||
const selections = JSONParser.safeParseJSON(result.content, []);
|
||||
|
||||
if (Array.isArray(selections)) {
|
||||
context.backgroundKnowledge = selections.filter((sel: any) =>
|
||||
@@ -347,21 +558,66 @@ class AIPipeline {
|
||||
concept: availableConcepts.find((c: any) => c.name === sel.conceptName),
|
||||
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;
|
||||
}
|
||||
|
||||
private async generateFinalRecommendations(context: PipelineContext): Promise<MicroTaskResult> {
|
||||
private async generateFinalRecommendations(context: PipelineContext, pipelineStart: number): Promise<MicroTaskResult> {
|
||||
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 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
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async completeUnderrepresentedPhases(context: PipelineContext, toolsData: any): Promise<void> {
|
||||
private async completeUnderrepresentedPhases(context: PipelineContext, toolsData: any, pipelineStart: number): Promise<void> {
|
||||
const phases = toolsData.phases || [];
|
||||
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(', '));
|
||||
|
||||
// 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) {
|
||||
await this.completePhaseWithSemanticSearch(context, phase, toolsData);
|
||||
await this.completePhaseWithSemanticSearch(context, phase, toolsData, pipelineStart);
|
||||
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 phaseQuery = `forensic ${phase.name.toLowerCase()} tools methods`;
|
||||
|
||||
@@ -397,6 +674,19 @@ class AIPipeline {
|
||||
try {
|
||||
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) {
|
||||
console.log('[AI-PIPELINE] No semantic results for phase:', phase.id);
|
||||
return;
|
||||
@@ -422,7 +712,7 @@ class AIPipeline {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add tools with justification
|
||||
// Add tools with justification and audit each addition
|
||||
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.`;
|
||||
|
||||
@@ -436,11 +726,40 @@ class AIPipeline {
|
||||
['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);
|
||||
}
|
||||
|
||||
} catch (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 || []
|
||||
);
|
||||
|
||||
// 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 {
|
||||
name: st.tool.name,
|
||||
type: st.tool.type,
|
||||
@@ -508,6 +839,17 @@ class AIPipeline {
|
||||
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 {
|
||||
name: st.tool.name,
|
||||
type: st.tool.type,
|
||||
@@ -532,7 +874,12 @@ class AIPipeline {
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
let contextPrompt = prompt;
|
||||
@@ -549,15 +896,16 @@ class AIPipeline {
|
||||
const response = await aiService.callMicroTaskAI(contextPrompt, maxTokens);
|
||||
|
||||
return {
|
||||
taskType: 'micro-task',
|
||||
taskType,
|
||||
content: response.content,
|
||||
processingTimeMs: Date.now() - startTime,
|
||||
success: true
|
||||
success: true,
|
||||
aiUsage: response.usage
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
return {
|
||||
taskType: 'micro-task',
|
||||
taskType,
|
||||
content: '',
|
||||
processingTimeMs: Date.now() - startTime,
|
||||
success: false,
|
||||
@@ -608,48 +956,21 @@ class AIPipeline {
|
||||
return 'low';
|
||||
}
|
||||
|
||||
private safeParseJSON(jsonString: string, fallback: any = null): any {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return JSON.parse(cleaned);
|
||||
|
||||
} catch (error) {
|
||||
console.warn('[AI-PIPELINE] JSON parsing failed:', error.message);
|
||||
return fallback;
|
||||
private truncateForAudit(text: string, maxLength: number = 200): string {
|
||||
if (typeof text !== 'string') return String(text);
|
||||
if (text.length <= maxLength) return text;
|
||||
return text.slice(0, maxLength) + '...[audit-truncated]';
|
||||
}
|
||||
|
||||
private trackTokenUsage(usage?: { promptTokens?: number; completionTokens?: number; totalTokens?: number }): void {
|
||||
if (usage?.totalTokens) {
|
||||
this.totalTokensUsed += usage.totalTokens;
|
||||
}
|
||||
}
|
||||
|
||||
private async delay(ms: number): Promise<void> {
|
||||
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();
|
||||
|
||||
Reference in New Issue
Block a user