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);
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:
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 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:
- Forensisch spezifisch, nicht allgemein (NICHT: "Mehr Details?")
- 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
ANTWORTFORMAT (NUR JSON, KEIN ZUSÄTZLICHER TEXT):
@ -116,7 +116,6 @@ export const POST: APIRoute = async ({ request }) => {
const aiResponse = await enqueueApiCall(() =>
aiService.callAI(systemPrompt, {
maxTokens: 300,
temperature: 0.7
}), taskId);

View File

@ -107,7 +107,6 @@ class AIPipeline {
const aiConfig = aiService.getConfig();
const toolsDataHash = getDataVersion?.() || 'unknown';
// Record the tools.yaml version being used
auditService.addEntry(
'initialization',
'tools-data-loaded',
@ -747,7 +746,7 @@ class AIPipeline {
prompt,
result.content,
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,
{
toolsDataHash: toolsDataHash,
@ -1184,21 +1183,18 @@ class AIPipeline {
try {
const response = await aiService.callMicroTaskAI(contextPrompt);
// FIX: Ensure ALL AI calls generate audit entries
const toolsDataHash = getDataVersion?.() || 'unknown';
const aiConfig = aiService.getConfig();
// Calculate response confidence for audit trail
const responseConfidence = auditService.calculateAIResponseConfidence(
response.content,
this.getExpectedLengthForTaskType(taskType),
taskType
);
// FIX: Always add AI decision audit entry for micro-tasks
auditService.addAIDecision(
this.getPhaseForTaskType(taskType),
prompt, // Store original prompt without context
prompt,
response.content,
responseConfidence,
this.getReasoningForTaskType(taskType, response.content),
@ -1224,7 +1220,6 @@ class AIPipeline {
};
} catch (error) {
// FIX: Also audit failed AI calls for completeness
auditService.addEntry(
this.getPhaseForTaskType(taskType),
'ai-decision-failed',
@ -1237,7 +1232,7 @@ class AIPipeline {
error: error.message,
success: false
},
0, // Zero confidence for failed calls
0,
startTime,
{
toolsDataHash: getDataVersion?.() || 'unknown',
@ -1299,7 +1294,7 @@ class AIPipeline {
};
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 {

View File

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

View File

@ -31,7 +31,6 @@ interface EmbeddingsDatabase {
}
interface EmbeddingsConfig {
//enabled: boolean;
endpoint?: string;
apiKey?: string;
model?: string;
@ -49,14 +48,12 @@ class EmbeddingsService {
constructor() {
this.config = this.loadConfig();
console.log('[EMBEDDINGS-SERVICE] Initialized:', {
//enabled: this.config.enabled,
hasEndpoint: !!this.config.endpoint,
hasModel: !!this.config.model
});
}
private loadConfig(): EmbeddingsConfig {
//const enabled = process.env.AI_EMBEDDINGS_ENABLED === 'true';
const endpoint = process.env.AI_EMBEDDINGS_ENDPOINT;
const apiKey = process.env.AI_EMBEDDINGS_API_KEY;
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);
return {
//enabled,
endpoint,
apiKey,
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 } {
return {
//enabled: this.config.enabled,
initialized: this.isInitialized,
count: this.embeddings.length
};

View File

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