This commit is contained in:
overcuriousity 2025-08-18 00:57:57 +02:00
parent 1d91dbf478
commit 6160620e24
5 changed files with 13 additions and 54 deletions

View File

@ -51,7 +51,7 @@ function cleanupExpiredRateLimits(): void {
setInterval(cleanupExpiredRateLimits, 5 * 60 * 1000); setInterval(cleanupExpiredRateLimits, 5 * 60 * 1000);
function createEnhancementPrompt(input: string): string { function createEnhancementPrompt(input: string): string {
return `Sie sind ein DFIR-Experte mit Spezialisierung auf forensische Methodik. Ein Nutzer beschreibt ein forensisches Szenario oder Problem. Analysieren Sie die Eingabe auf Vollständigkeit für eine wissenschaftlich fundierte forensische Untersuchung. return `Sie sind ein DFIR-Experte mit Spezialisierung auf forensische Methodik. Ein Nutzer beschreibt ein Szenario oder Problem. Analysieren Sie die Eingabe auf Vollständigkeit für eine wissenschaftlich fundierte Untersuchung.
ANALYSIEREN SIE DIESE FORENSISCHEN KATEGORIEN: ANALYSIEREN SIE DIESE FORENSISCHEN KATEGORIEN:
1. **Incident Context**: Was ist passiert? Welche Angriffsvektoren oder technischen Probleme liegen vor? 1. **Incident Context**: Was ist passiert? Welche Angriffsvektoren oder technischen Probleme liegen vor?
@ -64,12 +64,12 @@ ANALYSIEREN SIE DIESE FORENSISCHEN KATEGORIEN:
WENN die Beschreibung alle kritischen forensischen Aspekte abdeckt: Geben Sie eine leere Liste [] zurück. WENN die Beschreibung alle kritischen forensischen Aspekte abdeckt: Geben Sie eine leere Liste [] zurück.
WENN wichtige forensische Details fehlen: Formulieren Sie 2-3 präzise Fragen, die die kritischsten Lücken für eine wissenschaftlich fundierte forensische Analyse schließen. WENN wichtige Details fehlen: Formulieren Sie 2-3 präzise Fragen, die die kritischsten Lücken für eine wissenschaftlich fundierte Analyse schließen.
QUALITÄTSKRITERIEN FÜR FRAGEN: QUALITÄTSKRITERIEN FÜR FRAGEN:
- Forensisch spezifisch, nicht allgemein (NICHT: "Mehr Details?") - Forensisch spezifisch, nicht allgemein (NICHT: "Mehr Details?")
- Methodisch relevant (NICHT: "Wann passierte das?") - Methodisch relevant (NICHT: "Wann passierte das?")
- Priorisiert nach Auswirkung auf die forensische Untersuchungsqualität - Priorisiert nach Auswirkung auf die Untersuchungsqualität
- Die Frage soll maximal 20 Wörter umfassen - Die Frage soll maximal 20 Wörter umfassen
ANTWORTFORMAT (NUR JSON, KEIN ZUSÄTZLICHER TEXT): ANTWORTFORMAT (NUR JSON, KEIN ZUSÄTZLICHER TEXT):
@ -116,7 +116,6 @@ export const POST: APIRoute = async ({ request }) => {
const aiResponse = await enqueueApiCall(() => const aiResponse = await enqueueApiCall(() =>
aiService.callAI(systemPrompt, { aiService.callAI(systemPrompt, {
maxTokens: 300,
temperature: 0.7 temperature: 0.7
}), taskId); }), taskId);

View File

@ -107,7 +107,6 @@ class AIPipeline {
const aiConfig = aiService.getConfig(); const aiConfig = aiService.getConfig();
const toolsDataHash = getDataVersion?.() || 'unknown'; const toolsDataHash = getDataVersion?.() || 'unknown';
// Record the tools.yaml version being used
auditService.addEntry( auditService.addEntry(
'initialization', 'initialization',
'tools-data-loaded', 'tools-data-loaded',
@ -747,7 +746,7 @@ class AIPipeline {
prompt, prompt,
result.content, result.content,
confidence, confidence,
`Analysierte ${isWorkflow ? 'Szenario' : 'Problem'} basierend auf Nutzereingabe: "${context.userQuery.slice(0, 100)}..." - Identifizierte Kernaspekte und Herausforderungen für forensische Untersuchung`, `Analysierte ${isWorkflow ? 'Szenario' : 'Problem'} basierend auf Nutzereingabe: "${context.userQuery.slice(0, 100)}..." - Identifizierte Kernaspekte und Herausforderungen für Untersuchung`,
taskStart, taskStart,
{ {
toolsDataHash: toolsDataHash, toolsDataHash: toolsDataHash,
@ -1184,21 +1183,18 @@ class AIPipeline {
try { try {
const response = await aiService.callMicroTaskAI(contextPrompt); const response = await aiService.callMicroTaskAI(contextPrompt);
// FIX: Ensure ALL AI calls generate audit entries
const toolsDataHash = getDataVersion?.() || 'unknown'; const toolsDataHash = getDataVersion?.() || 'unknown';
const aiConfig = aiService.getConfig(); const aiConfig = aiService.getConfig();
// Calculate response confidence for audit trail
const responseConfidence = auditService.calculateAIResponseConfidence( const responseConfidence = auditService.calculateAIResponseConfidence(
response.content, response.content,
this.getExpectedLengthForTaskType(taskType), this.getExpectedLengthForTaskType(taskType),
taskType taskType
); );
// FIX: Always add AI decision audit entry for micro-tasks
auditService.addAIDecision( auditService.addAIDecision(
this.getPhaseForTaskType(taskType), this.getPhaseForTaskType(taskType),
prompt, // Store original prompt without context prompt,
response.content, response.content,
responseConfidence, responseConfidence,
this.getReasoningForTaskType(taskType, response.content), this.getReasoningForTaskType(taskType, response.content),
@ -1224,7 +1220,6 @@ class AIPipeline {
}; };
} catch (error) { } catch (error) {
// FIX: Also audit failed AI calls for completeness
auditService.addEntry( auditService.addEntry(
this.getPhaseForTaskType(taskType), this.getPhaseForTaskType(taskType),
'ai-decision-failed', 'ai-decision-failed',
@ -1237,7 +1232,7 @@ class AIPipeline {
error: error.message, error: error.message,
success: false success: false
}, },
0, // Zero confidence for failed calls 0,
startTime, startTime,
{ {
toolsDataHash: getDataVersion?.() || 'unknown', toolsDataHash: getDataVersion?.() || 'unknown',
@ -1299,7 +1294,7 @@ class AIPipeline {
}; };
const taskName = taskNames[taskType] || taskType; const taskName = taskNames[taskType] || taskType;
return `KI generierte ${taskName} (${responseLength} Zeichen) - forensisch fundierte Analyse mit methodischer Begründung`; return `KI generierte ${taskName} (${responseLength} Zeichen) - Analyse mit methodischer Begründung`;
} }
private addToContextHistory(context: PipelineContext, newEntry: string): void { private addToContextHistory(context: PipelineContext, newEntry: string): void {

View File

@ -26,7 +26,6 @@ export interface AuditEntry {
completionTokens?: number; completionTokens?: number;
toolsDataHash?: string; toolsDataHash?: string;
embeddingsUsed?: boolean; embeddingsUsed?: boolean;
//selectionMethod?: string;
microTaskType?: string; microTaskType?: string;
confidenceFactors?: string[]; confidenceFactors?: string[];
reasoning?: string; reasoning?: string;
@ -129,15 +128,15 @@ class AuditService {
this.addEntry( this.addEntry(
phase, phase,
'ai-decision', 'ai-decision',
{ prompt: this.createPromptSummary(aiPrompt) }, // Summary for display only { prompt: this.createPromptSummary(aiPrompt) },
{ response: aiResponse }, // STORE FULL RESPONSE - NO TRUNCATION { response: aiResponse },
confidence, confidence,
startTime, startTime,
{ {
...metadata, ...metadata,
reasoning, reasoning,
aiPrompt: aiPrompt, // Full prompt in metadata aiPrompt: aiPrompt,
aiResponse: aiResponse, // Full response in metadata aiResponse: aiResponse,
decisionBasis: 'ai-analysis' decisionBasis: 'ai-analysis'
} }
); );
@ -146,7 +145,6 @@ class AuditService {
addToolSelection( addToolSelection(
selectedTools: string[], selectedTools: string[],
availableTools: string[], availableTools: string[],
//selectionMethod: string,
confidence: number, confidence: number,
startTime: number, startTime: number,
metadata: Record<string, any> = {} metadata: Record<string, any> = {}
@ -154,7 +152,6 @@ class AuditService {
const calculatedConfidence = this.calculateSelectionConfidence( const calculatedConfidence = this.calculateSelectionConfidence(
selectedTools, selectedTools,
availableTools, availableTools,
//selectionMethod,
metadata metadata
); );
@ -169,7 +166,6 @@ class AuditService {
{ {
availableTools: availableTools.slice(0, 10), availableTools: availableTools.slice(0, 10),
totalAvailable: availableTools.length, totalAvailable: availableTools.length,
//selectionMethod: selectionMethod
}, },
{ {
selectedTools: selectedTools, selectedTools: selectedTools,
@ -179,10 +175,8 @@ class AuditService {
startTime, startTime,
{ {
...metadata, ...metadata,
//selectionMethod,
availableToolsCount: availableTools.length, availableToolsCount: availableTools.length,
selectedToolsCount: selectedTools.length, selectedToolsCount: selectedTools.length,
//decisionBasis: selectionMethod.includes('embeddings') ? 'semantic-search' : 'ai-analysis'
decisionBasis decisionBasis
} }
); );
@ -288,7 +282,6 @@ class AuditService {
private calculateSelectionConfidence( private calculateSelectionConfidence(
selectedTools: string[], selectedTools: string[],
availableTools: string[], availableTools: string[],
//selectionMethod: string,
metadata: Record<string, any> metadata: Record<string, any>
): number { ): number {
let confidence = 50; let confidence = 50;
@ -303,10 +296,6 @@ class AuditService {
confidence -= 20; confidence -= 20;
} }
/*if (selectionMethod.includes('embeddings')) {
confidence += 15;
}*/
if (selectedTools.length >= 5 && selectedTools.length <= 25) { if (selectedTools.length >= 5 && selectedTools.length <= 25) {
confidence += 10; confidence += 10;
} }
@ -562,9 +551,9 @@ class AuditService {
'background-knowledge': 'Hintergrundwissen-Auswahl', 'background-knowledge': 'Hintergrundwissen-Auswahl',
'final-recommendations': 'Abschließende Empfehlungen' 'final-recommendations': 'Abschließende Empfehlungen'
}; };
return `KI analysierte ${typeNames[taskType] || taskType} mit ${confidence}% Vertrauen - fundierte forensische Methodikempfehlung`; return `KI analysierte ${typeNames[taskType] || taskType} mit ${confidence}% Vertrauen - fundierte Empfehlung`;
} }
return `KI-Entscheidung mit ${confidence}% Vertrauen basierend auf forensischer Expertenanalyse`; return `KI-Entscheidung mit ${confidence}% Vertrauen basierend auf agentischer Expertenanalyse`;
case 'phase-enhancement': case 'phase-enhancement':
const phaseData = input?.phaseName || input?.phaseId; const phaseData = input?.phaseName || input?.phaseId;
@ -593,7 +582,6 @@ class AuditService {
private inferDecisionBasis(metadata: Record<string, any>): string { private inferDecisionBasis(metadata: Record<string, any>): string {
if (metadata.embeddingsUsed) return 'semantic-search'; if (metadata.embeddingsUsed) return 'semantic-search';
//if (metadata.embeddingsUsed || metadata.selectionMethod?.includes('embeddings')) return 'semantic-search';
if (metadata.aiPrompt || metadata.microTaskType) return 'ai-analysis'; if (metadata.aiPrompt || metadata.microTaskType) return 'ai-analysis';
if (metadata.semanticQuery && metadata.aiReasoningUsed) return 'hybrid'; if (metadata.semanticQuery && metadata.aiReasoningUsed) return 'hybrid';
return 'rule-based'; return 'rule-based';

View File

@ -31,7 +31,6 @@ interface EmbeddingsDatabase {
} }
interface EmbeddingsConfig { interface EmbeddingsConfig {
//enabled: boolean;
endpoint?: string; endpoint?: string;
apiKey?: string; apiKey?: string;
model?: string; model?: string;
@ -49,14 +48,12 @@ class EmbeddingsService {
constructor() { constructor() {
this.config = this.loadConfig(); this.config = this.loadConfig();
console.log('[EMBEDDINGS-SERVICE] Initialized:', { console.log('[EMBEDDINGS-SERVICE] Initialized:', {
//enabled: this.config.enabled,
hasEndpoint: !!this.config.endpoint, hasEndpoint: !!this.config.endpoint,
hasModel: !!this.config.model hasModel: !!this.config.model
}); });
} }
private loadConfig(): EmbeddingsConfig { private loadConfig(): EmbeddingsConfig {
//const enabled = process.env.AI_EMBEDDINGS_ENABLED === 'true';
const endpoint = process.env.AI_EMBEDDINGS_ENDPOINT; const endpoint = process.env.AI_EMBEDDINGS_ENDPOINT;
const apiKey = process.env.AI_EMBEDDINGS_API_KEY; const apiKey = process.env.AI_EMBEDDINGS_API_KEY;
const model = process.env.AI_EMBEDDINGS_MODEL; const model = process.env.AI_EMBEDDINGS_MODEL;
@ -64,7 +61,6 @@ class EmbeddingsService {
const batchDelay = parseInt(process.env.AI_EMBEDDINGS_BATCH_DELAY_MS || '1000', 10); const batchDelay = parseInt(process.env.AI_EMBEDDINGS_BATCH_DELAY_MS || '1000', 10);
return { return {
//enabled,
endpoint, endpoint,
apiKey, apiKey,
model, model,
@ -344,21 +340,8 @@ class EmbeddingsService {
} }
} }
/*isEnabled(): boolean {
return this.config.enabled;
}*/
/*getStats(): { enabled: boolean; initialized: boolean; count: number } {
return {
enabled: this.config.enabled,
initialized: this.isInitialized,
count: this.embeddings.length
};
}*/
getStats(): {initialized: boolean; count: number } { getStats(): {initialized: boolean; count: number } {
return { return {
//enabled: this.config.enabled,
initialized: this.isInitialized, initialized: this.isInitialized,
count: this.embeddings.length count: this.embeddings.length
}; };

View File

@ -99,7 +99,6 @@ class ToolSelector {
console.log('[TOOL-SELECTOR] Using embeddings for candidate selection'); console.log('[TOOL-SELECTOR] Using embeddings for candidate selection');
// FIX: Record the start time for audit trail
const embeddingsSearchStart = Date.now(); const embeddingsSearchStart = Date.now();
const similarItems = await embeddingsService.findSimilar( const similarItems = await embeddingsService.findSimilar(
@ -110,13 +109,11 @@ class ToolSelector {
console.log('[TOOL-SELECTOR] Embeddings found', similarItems.length, 'similar items'); console.log('[TOOL-SELECTOR] Embeddings found', similarItems.length, 'similar items');
// FIX: Import and use auditService to record this embeddings search
const { auditService } = await import('./auditService.js'); const { auditService } = await import('./auditService.js');
const { getDataVersion } = await import('./dataService.js'); const { getDataVersion } = await import('./dataService.js');
const toolsDataHash = getDataVersion() || 'unknown'; const toolsDataHash = getDataVersion() || 'unknown';
// FIX: Add audit entry for initial embeddings search that happens in BOTH modes
auditService.addEmbeddingsSearch( auditService.addEmbeddingsSearch(
userQuery, userQuery,
similarItems, similarItems,
@ -197,13 +194,11 @@ class ToolSelector {
const softwareWithFullData = candidateSoftware.map(this.createToolData); const softwareWithFullData = candidateSoftware.map(this.createToolData);
const conceptsWithFullData = candidateConcepts.map(this.createConceptData); const conceptsWithFullData = candidateConcepts.map(this.createConceptData);
// Unified selection limits (method-agnostic)
const maxTools = Math.min(this.config.embeddingSelectionLimit, this.config.noEmbeddingsToolLimit); const maxTools = Math.min(this.config.embeddingSelectionLimit, this.config.noEmbeddingsToolLimit);
const maxConcepts = Math.min(this.config.embeddingConceptsLimit, this.config.noEmbeddingsConceptLimit); const maxConcepts = Math.min(this.config.embeddingConceptsLimit, this.config.noEmbeddingsConceptLimit);
const methodLimit = Math.ceil(maxTools * this.config.methodSelectionRatio); const methodLimit = Math.ceil(maxTools * this.config.methodSelectionRatio);
const softwareLimit = Math.floor(maxTools * this.config.softwareSelectionRatio); const softwareLimit = Math.floor(maxTools * this.config.softwareSelectionRatio);
// Build tool list to send
const toolsToSend: any[] = [ const toolsToSend: any[] = [
...methodsWithFullData.slice(0, methodLimit), ...methodsWithFullData.slice(0, methodLimit),
...softwareWithFullData.slice(0, softwareLimit), ...softwareWithFullData.slice(0, softwareLimit),
@ -211,7 +206,6 @@ class ToolSelector {
const remainingCapacity = maxTools - toolsToSend.length; const remainingCapacity = maxTools - toolsToSend.length;
if (remainingCapacity > 0) { if (remainingCapacity > 0) {
// Fill remainder from whichever bucket still has items
const extraMethods = methodsWithFullData.slice(methodLimit, methodLimit + remainingCapacity); const extraMethods = methodsWithFullData.slice(methodLimit, methodLimit + remainingCapacity);
const extraSoftware = softwareWithFullData.slice(softwareLimit, softwareLimit + (remainingCapacity - extraMethods.length)); const extraSoftware = softwareWithFullData.slice(softwareLimit, softwareLimit + (remainingCapacity - extraMethods.length));
toolsToSend.push(...extraMethods, ...extraSoftware); toolsToSend.push(...extraMethods, ...extraSoftware);