This commit is contained in:
overcuriousity
2025-08-16 22:03:40 +02:00
parent 0c7c502b03
commit 77f09ed399
8 changed files with 1392 additions and 231 deletions

View File

@@ -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();