first iteration - buggy

This commit is contained in:
overcuriousity
2025-08-16 18:15:20 +02:00
parent 1d98dd3257
commit 0c7c502b03
12 changed files with 1939 additions and 2437 deletions

View File

@@ -1,4 +1,4 @@
// src/utils/auditService.ts
// src/utils/auditService.ts - Refactored
import 'dotenv/config';
function env(key: string, fallback: string | undefined = undefined): string | undefined {
@@ -11,7 +11,6 @@ function env(key: string, fallback: string | undefined = undefined): string | un
return fallback;
}
// CONSOLIDATED AUDIT INTERFACES - Single source of truth
export interface AuditEntry {
timestamp: number;
phase: string;
@@ -30,63 +29,9 @@ interface AuditConfig {
maxEntries: number;
}
interface CompressedAuditEntry {
timestamp: number;
phase: string;
action: string;
inputSummary: string;
outputSummary: string;
confidence: number;
processingTimeMs: number;
metadata: Record<string, any>;
}
export interface ProcessedAuditTrail {
totalTime: number;
avgConfidence: number;
stepCount: number;
highConfidenceSteps: number;
lowConfidenceSteps: number;
phases: Array<{
name: string;
icon: string;
displayName: string;
avgConfidence: number;
totalTime: number;
entries: CompressedAuditEntry[];
}>;
summary: {
analysisQuality: 'excellent' | 'good' | 'fair' | 'poor';
keyInsights: string[];
potentialIssues: string[];
};
}
class AuditService {
private config: AuditConfig;
private activeAuditTrail: AuditEntry[] = [];
private readonly phaseConfig = {
'initialization': { icon: '🚀', displayName: 'Initialisierung' },
'retrieval': { icon: '🔍', displayName: 'Datensuche' },
'selection': { icon: '🎯', displayName: 'Tool-Auswahl' },
'micro-task': { icon: '⚡', displayName: 'Detail-Analyse' },
'validation': { icon: '✓', displayName: 'Validierung' },
'completion': { icon: '✅', displayName: 'Finalisierung' }
};
private readonly actionTranslations = {
'pipeline-start': 'Analyse gestartet',
'embeddings-search': 'Ähnliche Tools gesucht',
'ai-tool-selection': 'Tools automatisch ausgewählt',
'ai-analysis': 'KI-Analyse durchgeführt',
'phase-tool-selection': 'Phasen-Tools evaluiert',
'tool-evaluation': 'Tool-Bewertung erstellt',
'background-knowledge-selection': 'Hintergrundwissen ausgewählt',
'confidence-scoring': 'Vertrauenswertung berechnet',
'phase-completion': 'Phasenergänzung durchgeführt',
'pipeline-end': 'Analyse abgeschlossen'
};
constructor() {
this.config = this.loadConfig();
@@ -110,7 +55,6 @@ class AuditService {
};
}
// CONSOLIDATED AUDIT ENTRY CREATION - Single method for all audit operations
addEntry(
phase: string,
action: string,
@@ -134,15 +78,19 @@ class AuditService {
};
this.activeAuditTrail.push(entry);
// Enforce max entries limit
if (this.activeAuditTrail.length > this.config.maxEntries) {
this.activeAuditTrail.shift();
}
console.log(`[AUDIT-SERVICE] ${phase}/${action}: ${confidence}% confidence, ${entry.processingTimeMs}ms`);
}
// GET CURRENT AUDIT TRAIL - For integration with AI pipeline
getCurrentAuditTrail(): AuditEntry[] {
return [...this.activeAuditTrail];
}
// CLEAR AUDIT TRAIL - Start fresh for new analysis
clearAuditTrail(): void {
if (this.activeAuditTrail.length > 0) {
console.log(`[AUDIT-SERVICE] Cleared ${this.activeAuditTrail.length} audit entries`);
@@ -150,7 +98,6 @@ class AuditService {
}
}
// FINALIZE AUDIT TRAIL - Complete analysis and return final trail
finalizeAuditTrail(): AuditEntry[] {
const finalTrail = [...this.activeAuditTrail];
console.log(`[AUDIT-SERVICE] Finalized audit trail with ${finalTrail.length} entries`);
@@ -158,102 +105,6 @@ class AuditService {
return finalTrail;
}
processAuditTrail(rawAuditTrail: AuditEntry[]): ProcessedAuditTrail | null {
if (!this.config.enabled) {
console.log('[AUDIT-SERVICE] Processing disabled');
return null;
}
if (!rawAuditTrail || !Array.isArray(rawAuditTrail) || rawAuditTrail.length === 0) {
console.log('[AUDIT-SERVICE] No audit trail data to process');
return null;
}
try {
console.log(`[AUDIT-SERVICE] Processing ${rawAuditTrail.length} audit entries`);
const totalTime = rawAuditTrail.reduce((sum, entry) => sum + (entry.processingTimeMs || 0), 0);
const validConfidenceEntries = rawAuditTrail.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 highConfidenceSteps = rawAuditTrail.filter(entry => (entry.confidence || 0) >= 80).length;
const lowConfidenceSteps = rawAuditTrail.filter(entry => (entry.confidence || 0) < 60).length;
const groupedEntries = rawAuditTrail.reduce((groups, entry) => {
const phase = entry.phase || 'unknown';
if (!groups[phase]) groups[phase] = [];
groups[phase].push(entry);
return groups;
}, {} as Record<string, AuditEntry[]>);
const phases = Object.entries(groupedEntries).map(([phase, entries]) => {
const phaseConfig = this.phaseConfig[phase] || { icon: '📋', displayName: phase };
const validEntries = entries.filter(entry => entry && typeof entry === 'object');
const phaseAvgConfidence = validEntries.length > 0
? Math.round(validEntries.reduce((sum, entry) => sum + (entry.confidence || 0), 0) / validEntries.length)
: 0;
const phaseTotalTime = validEntries.reduce((sum, entry) => sum + (entry.processingTimeMs || 0), 0);
return {
name: phase,
icon: phaseConfig.icon,
displayName: phaseConfig.displayName,
avgConfidence: phaseAvgConfidence,
totalTime: phaseTotalTime,
entries: validEntries
.map(e => this.compressEntry(e))
.filter((e): e is CompressedAuditEntry => e !== null)
};
}).filter(phase => phase.entries.length > 0);
const summary = this.generateSummary(rawAuditTrail, avgConfidence, lowConfidenceSteps);
const result: ProcessedAuditTrail = {
totalTime,
avgConfidence,
stepCount: rawAuditTrail.length,
highConfidenceSteps,
lowConfidenceSteps,
phases,
summary
};
console.log(`[AUDIT-SERVICE] Successfully processed audit trail: ${result.phases.length} phases, ${result.avgConfidence}% avg confidence`);
return result;
} catch (error) {
console.error('[AUDIT-SERVICE] Error processing audit trail:', error);
return null;
}
}
private compressEntry(entry: AuditEntry): CompressedAuditEntry | null {
if (!entry || typeof entry !== 'object') {
console.warn('[AUDIT-SERVICE] Invalid audit entry skipped');
return null;
}
try {
return {
timestamp: entry.timestamp || Date.now(),
phase: entry.phase || 'unknown',
action: entry.action || 'unknown',
inputSummary: this.summarizeData(entry.input),
outputSummary: this.summarizeData(entry.output),
confidence: entry.confidence || 0,
processingTimeMs: entry.processingTimeMs || 0,
metadata: entry.metadata || {}
};
} catch (error) {
console.error('[AUDIT-SERVICE] Error compressing entry:', error);
return null;
}
}
private compressData(data: any): any {
if (this.config.detailLevel === 'verbose') {
return data;
@@ -264,30 +115,6 @@ class AuditService {
}
}
private summarizeData(data: any): string {
if (data === null || data === undefined) return 'null';
if (typeof data === 'string') {
return data.length > 100 ? data.slice(0, 100) + '...' : data;
}
if (typeof data === 'number' || typeof data === 'boolean') {
return data.toString();
}
if (Array.isArray(data)) {
if (data.length === 0) return '[]';
if (data.length <= 3) return JSON.stringify(data);
return `[${data.slice(0, 3).map(i => typeof i === 'string' ? i : JSON.stringify(i)).join(', ')}, ...+${data.length - 3}]`;
}
if (typeof data === 'object') {
const keys = Object.keys(data);
if (keys.length === 0) return '{}';
if (keys.length <= 3) {
return '{' + keys.map(k => `${k}: ${typeof data[k] === 'string' ? data[k].slice(0, 20) + (data[k].length > 20 ? '...' : '') : JSON.stringify(data[k])}`).join(', ') + '}';
}
return `{${keys.slice(0, 3).join(', ')}, ...+${keys.length - 3} keys}`;
}
return String(data);
}
private summarizeForStorage(data: any): any {
if (typeof data === 'string' && data.length > 500) {
return data.slice(0, 500) + '...[truncated]';
@@ -308,71 +135,6 @@ class AuditService {
return data;
}
private generateSummary(entries: AuditEntry[], avgConfidence: number, lowConfidenceSteps: number): {
analysisQuality: 'excellent' | 'good' | 'fair' | 'poor';
keyInsights: string[];
potentialIssues: string[];
} {
let analysisQuality: 'excellent' | 'good' | 'fair' | 'poor';
if (avgConfidence >= 85 && lowConfidenceSteps === 0) {
analysisQuality = 'excellent';
} else if (avgConfidence >= 70 && lowConfidenceSteps <= 1) {
analysisQuality = 'good';
} else if (avgConfidence >= 60 && lowConfidenceSteps <= 3) {
analysisQuality = 'fair';
} else {
analysisQuality = 'poor';
}
const keyInsights: string[] = [];
const embeddingsUsed = entries.some(e => e.action === 'embeddings-search');
if (embeddingsUsed) {
keyInsights.push('Semantische Suche wurde erfolgreich eingesetzt');
}
const toolSelectionEntries = entries.filter(e => e.action === 'ai-tool-selection');
if (toolSelectionEntries.length > 0) {
const avgSelectionConfidence = toolSelectionEntries.reduce((sum, e) => sum + e.confidence, 0) / toolSelectionEntries.length;
if (avgSelectionConfidence >= 80) {
keyInsights.push('Hohe Konfidenz bei der Tool-Auswahl');
}
}
const potentialIssues: string[] = [];
if (lowConfidenceSteps > 2) {
potentialIssues.push(`${lowConfidenceSteps} Analyseschritte mit niedriger Konfidenz`);
}
const longSteps = entries.filter(e => e.processingTimeMs > 5000);
if (longSteps.length > 0) {
potentialIssues.push(`${longSteps.length} Schritte benötigten mehr als 5 Sekunden`);
}
return {
analysisQuality,
keyInsights,
potentialIssues
};
}
getActionDisplayName(action: string): string {
return this.actionTranslations[action] || action;
}
formatDuration(ms: number): string {
if (ms < 1000) return '< 1s';
if (ms < 60000) return `${Math.ceil(ms / 1000)}s`;
const minutes = Math.floor(ms / 60000);
const seconds = Math.ceil((ms % 60000) / 1000);
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
}
getConfidenceColor(confidence: number): string {
if (confidence >= 80) return 'var(--color-accent)';
if (confidence >= 60) return 'var(--color-warning)';
return 'var(--color-error)';
}
isEnabled(): boolean {
return this.config.enabled;
}
@@ -380,7 +142,122 @@ class AuditService {
getConfig(): AuditConfig {
return { ...this.config };
}
// Statistics and analysis methods
getAuditStatistics(auditTrail: AuditEntry[]): {
totalTime: number;
avgConfidence: number;
stepCount: number;
highConfidenceSteps: number;
lowConfidenceSteps: number;
phaseBreakdown: Record<string, { count: number; avgConfidence: number; totalTime: number }>;
} {
if (!auditTrail || auditTrail.length === 0) {
return {
totalTime: 0,
avgConfidence: 0,
stepCount: 0,
highConfidenceSteps: 0,
lowConfidenceSteps: 0,
phaseBreakdown: {}
};
}
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 highConfidenceSteps = auditTrail.filter(entry => (entry.confidence || 0) >= 80).length;
const lowConfidenceSteps = auditTrail.filter(entry => (entry.confidence || 0) < 60).length;
// Phase breakdown
const phaseBreakdown: Record<string, { count: number; avgConfidence: number; totalTime: number }> = {};
auditTrail.forEach(entry => {
const phase = entry.phase || 'unknown';
if (!phaseBreakdown[phase]) {
phaseBreakdown[phase] = { count: 0, avgConfidence: 0, totalTime: 0 };
}
phaseBreakdown[phase].count++;
phaseBreakdown[phase].totalTime += entry.processingTimeMs || 0;
});
// Calculate average confidence per phase
Object.keys(phaseBreakdown).forEach(phase => {
const phaseEntries = auditTrail.filter(entry => entry.phase === phase);
const validEntries = phaseEntries.filter(entry => typeof entry.confidence === 'number');
if (validEntries.length > 0) {
phaseBreakdown[phase].avgConfidence = Math.round(
validEntries.reduce((sum, entry) => sum + entry.confidence, 0) / validEntries.length
);
}
});
return {
totalTime,
avgConfidence,
stepCount: auditTrail.length,
highConfidenceSteps,
lowConfidenceSteps,
phaseBreakdown
};
}
validateAuditTrail(auditTrail: AuditEntry[]): {
isValid: boolean;
issues: string[];
warnings: string[];
} {
const issues: string[] = [];
const warnings: string[] = [];
if (!Array.isArray(auditTrail)) {
issues.push('Audit trail is not an array');
return { isValid: false, issues, warnings };
}
if (auditTrail.length === 0) {
warnings.push('Audit trail is empty');
}
auditTrail.forEach((entry, index) => {
if (!entry || typeof entry !== 'object') {
issues.push(`Entry ${index} is not a valid object`);
return;
}
// Required fields validation
const requiredFields = ['timestamp', 'phase', 'action'];
requiredFields.forEach(field => {
if (!(field in entry)) {
issues.push(`Entry ${index} missing required field: ${field}`);
}
});
// Data type validation
if (typeof entry.confidence !== 'number' || entry.confidence < 0 || entry.confidence > 100) {
warnings.push(`Entry ${index} has invalid confidence value: ${entry.confidence}`);
}
if (typeof entry.processingTimeMs !== 'number' || entry.processingTimeMs < 0) {
warnings.push(`Entry ${index} has invalid processing time: ${entry.processingTimeMs}`);
}
if (typeof entry.timestamp !== 'number' || entry.timestamp <= 0) {
issues.push(`Entry ${index} has invalid timestamp: ${entry.timestamp}`);
}
});
return {
isValid: issues.length === 0,
issues,
warnings
};
}
}
export const auditService = new AuditService();
export type { CompressedAuditEntry };
export const auditService = new AuditService();