From 3d5d2506e9058c9905a206a1e9351ea94c5e6942 Mon Sep 17 00:00:00 2001 From: overcuriousity Date: Sun, 17 Aug 2025 23:45:28 +0200 Subject: [PATCH] fix false truncation --- src/components/AIQueryInterface.astro | 41 +++++++++++++++++++++++---- src/utils/auditService.ts | 33 ++++++++++----------- 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/src/components/AIQueryInterface.astro b/src/components/AIQueryInterface.astro index c9cba7b..6608db0 100644 --- a/src/components/AIQueryInterface.astro +++ b/src/components/AIQueryInterface.astro @@ -1194,7 +1194,7 @@ class AIQueryInterface { ) / responseQualityEntries.length; if (avgResponseQuality >= 70) { - keyInsights.push(`Hohe AI-Antwortqualität (Ø ${Math.round(avgResponseQuality)}%)`); + keyInsights.push(`Hohe AI-Antwortqualität (∅ ${Math.round(avgResponseQuality)}%)`); } } @@ -1203,12 +1203,41 @@ class AIQueryInterface { potentialIssues.push(`${lowConfidenceSteps} Analyseschritte mit niedriger Konfidenz`); } - const truncatedResponses = auditTrail.filter(e => - e.output && typeof e.output === 'object' && - e.output.response && e.output.response.includes('...') + // FIXED: Only detect actual AI incompleteness, not display truncation + // The old code incorrectly flagged display truncation as incomplete responses: + // OLD (WRONG): e.output.response && e.output.response.includes('...') + + // NEW (CORRECT): Check metadata.aiResponse for actual incompleteness + const incompleteAIResponses = auditTrail.filter(e => + e.action === 'ai-decision' && + e.metadata?.aiResponse && + ( + // Detect actual AI incompleteness patterns: + e.metadata.aiResponse.trim().length < 10 || // Very short response + e.metadata.aiResponse.endsWith('...') || // AI itself truncated (rare but possible) + e.metadata.aiResponse.includes('[TRUNCATED]') || // Explicit truncation marker + e.metadata.aiResponse.includes('I cannot continue') || // AI stopped unexpectedly + e.metadata.aiResponse.includes('I need to stop here') || // AI indicated incompleteness + e.metadata.aiResponse.includes('[RESPONSE_TOO_LONG]') || // Length limit hit + // Also check if the AI response seems cut off mid-sentence + (e.metadata.aiResponse.length > 50 && + !e.metadata.aiResponse.trim().match(/[.!?:]$/)) // Doesn't end with proper punctuation + ) ).length; - if (truncatedResponses > 0) { - potentialIssues.push(`${truncatedResponses} möglicherweise unvollständige AI-Antworten`); + + if (incompleteAIResponses > 0) { + potentialIssues.push(`${incompleteAIResponses} möglicherweise unvollständige AI-Antworten`); + } + + // Additional quality checks + const veryShortResponses = auditTrail.filter(e => + e.action === 'ai-decision' && + e.metadata?.aiResponse && + e.metadata.aiResponse.trim().length < 20 + ).length; + + if (veryShortResponses > 1) { + potentialIssues.push(`${veryShortResponses} ungewöhnlich kurze AI-Antworten`); } return { diff --git a/src/utils/auditService.ts b/src/utils/auditService.ts index e2bb98b..9cfffb6 100644 --- a/src/utils/auditService.ts +++ b/src/utils/auditService.ts @@ -129,15 +129,15 @@ class AuditService { this.addEntry( phase, 'ai-decision', - { prompt: this.truncatePrompt(aiPrompt) }, - { response: this.truncateResponse(aiResponse) }, + { prompt: this.createPromptSummary(aiPrompt) }, // Summary for display only + { response: aiResponse }, // STORE FULL RESPONSE - NO TRUNCATION confidence, startTime, { ...metadata, reasoning, - aiPrompt: aiPrompt, - aiResponse: aiResponse, + aiPrompt: aiPrompt, // Full prompt in metadata + aiResponse: aiResponse, // Full response in metadata decisionBasis: 'ai-analysis' } ); @@ -425,13 +425,13 @@ class AuditService { if (type === 'input') { if (data.prompt) { const promptPreview = data.prompt.slice(0, 80).replace(/\n/g, ' '); - return `KI-Prompt: ${promptPreview}...`; + return `KI-Prompt: ${promptPreview}${data.prompt.length > 80 ? ' [Vorschau]' : ''}`; } return 'KI-Analyse angefordert'; } else { if (data.response) { const responsePreview = data.response.slice(0, 80).replace(/\n/g, ' '); - return `KI-Antwort: ${responsePreview}...`; + return `KI-Antwort: ${responsePreview}${data.response.length > 80 ? ' [Vorschau]' : ''}`; } return 'KI-Analyse abgeschlossen'; } @@ -446,8 +446,10 @@ class AuditService { } case 'tool-added-to-phase': - if (type === 'input') { - return `${data.toolName} → ${data.phaseId} (${data.taskRelevance}% Relevanz, ${data.priority})`; + if (type === 'output') { + const justificationPreview = data.justification ? + data.justification.slice(0, 60).replace(/\n/g, ' ') + (data.justification.length > 60 ? ' [Vorschau]' : '') : 'Hinzugefügt'; + return `Begründung: ${justificationPreview}`; } else { const justificationPreview = data.justification ? data.justification.slice(0, 60).replace(/\n/g, ' ') + '...' : 'Hinzugefügt'; @@ -512,6 +514,11 @@ class AuditService { return String(data); } + private createPromptSummary(prompt: string): string { + if (!prompt || prompt.length <= 200) return prompt; + return prompt.slice(0, 200) + ' [Eingabe-Vorschau]'; + } + private generateSpecificReasoning( action: string, input: any, @@ -572,16 +579,6 @@ class AuditService { } } - private truncatePrompt(prompt: string): string { - if (!prompt || prompt.length <= 200) return prompt; - return prompt.slice(0, 200) + '...[gekürzt]'; - } - - private truncateResponse(response: string): string { - if (!response || response.length <= 300) return response; - return response.slice(0, 300) + '...[gekürzt]'; - } - private getPhaseDisplayName(phaseId: string): string { const phaseNames: Record = { 'preparation': 'Vorbereitung',