Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
96c2875
Fix OpenAI quota exhaustion error handling in RAG queries
leex279 Aug 19, 2025
2c16ed9
Remove unused variable to fix linting
leex279 Aug 19, 2025
f23faea
Add comprehensive frontend error handling for OpenAI API errors
leex279 Aug 19, 2025
c3a9548
Fix #362: Enhance OpenAI API error handling with sanitization and ret…
leex279 Aug 20, 2025
6652873
Implement code review findings: Security and performance improvements
leex279 Aug 20, 2025
3c0fc55
Fix OpenAI API key cache invalidation regression
leex279 Aug 21, 2025
5fbe8fb
Merge latest main into bugfix-issue-362 - Keep OpenAI error handling …
leex279 Aug 21, 2025
0a8bea6
Add comprehensive OpenAI AuthenticationError handling
leex279 Aug 21, 2025
f770675
Fix crawl success reporting when embeddings fail
leex279 Aug 21, 2025
c3cf1ee
RAG: surface OpenAI auth errors as 401; fix single-vector embedding c…
Aug 29, 2025
2c3b8ef
PR #521: address CodeRabbit review β€” consistent 401 payload; mask key…
Aug 29, 2025
46a98da
Merge PR 521: Fix authentication error handling in RAG
leex279 Aug 30, 2025
0fce8a5
Add upfront OpenAI API key validation to prevent wasted crawling
leex279 Aug 30, 2025
3337b90
Fix UI error display: restore enhanced error handling in KnowledgeBas…
leex279 Aug 30, 2025
de8aa8a
fix: Address CodeRabbit review comments
leex279 Aug 31, 2025
2ffe1ac
Merge latest main changes into OpenAI error handling branch
leex279 Aug 31, 2025
26d0588
fix: Improve UI error display for OpenAI authentication errors
leex279 Aug 31, 2025
afe8c56
fix: Add clear 401 status code to authentication error message
leex279 Aug 31, 2025
39451b7
debug: Add detailed logging to diagnose error parsing issue
leex279 Aug 31, 2025
071840a
fix: Use enhanced UI error messages directly in error parsing
leex279 Aug 31, 2025
71e83dd
fix: Address CodeRabbit review suggestions for error handling
leex279 Aug 31, 2025
3e09eba
fix: Resolve backend test failures
leex279 Aug 31, 2025
99375c6
fix: Update tests for fail-fast behavior and fix storage mocks
leex279 Aug 31, 2025
1f382e5
fix: Add comprehensive mocking to prevent real API calls in tests
leex279 Aug 31, 2025
7c8d3e4
fix: Correct chunk count in document storage test
leex279 Aug 31, 2025
5ef7c2f
fix: Remove non-existent EmbeddingResult import causing test collecti…
leex279 Aug 31, 2025
e1aec98
fix: Update tests to expect masked API key prefix
leex279 Aug 31, 2025
65c4363
fix: Allow test-specific mocking by removing autouse create_embedding…
leex279 Aug 31, 2025
9cc7023
fix: Mock search_documents directly to test error handling pipeline
leex279 Aug 31, 2025
efeaaab
Delete OPENAI_ERROR_HANDLING.md
leex279 Aug 31, 2025
7a3775a
fix: Address critical and warning issues from code review
leex279 Aug 31, 2025
ff16882
Merge origin/main into bugfix-issue-362
leex279 Sep 6, 2025
e5235e6
Fix missing import for enhanced error handling in KnowledgeBasePage
leex279 Sep 6, 2025
57ee971
Add debug logging to frontend error parsing
leex279 Sep 6, 2025
5562605
Merge remote-tracking branch 'origin/main' into bugfix-issue-362
leex279 Sep 6, 2025
63c51e3
fix: Address ReDoS vulnerability in regex patterns
leex279 Sep 6, 2025
80e0cff
fix: Optimize isSafeObject performance in error handler
leex279 Sep 6, 2025
faf5ece
fix: Add frontend sanitization for sensitive data in error messages
leex279 Sep 6, 2025
9c85295
fix: Sanitize string error messages to prevent sensitive data leakage
leex279 Sep 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions archon-ui-main/src/components/ui/Alert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Basic Alert component for error display
*
* Provides consistent styling for alerts throughout the application.
*/

import React from 'react';

interface AlertProps {
children: React.ReactNode;
variant?: 'default' | 'destructive';
className?: string;
}

export const Alert: React.FC<AlertProps> = ({
children,
variant = 'default',
className = ''
}) => {
const baseClasses = 'p-4 border rounded-lg';
const variantClasses = variant === 'destructive'
? 'border-red-300 bg-red-50 text-red-800'
: 'border-blue-300 bg-blue-50 text-blue-800';

return (
<div className={`${baseClasses} ${variantClasses} ${className}`}>
{children}
</div>
);
};

interface AlertDescriptionProps {
children: React.ReactNode;
className?: string;
}

export const AlertDescription: React.FC<AlertDescriptionProps> = ({
children,
className = ''
}) => {
return (
<div className={className}>
{children}
</div>
);
};
162 changes: 162 additions & 0 deletions archon-ui-main/src/components/ui/ErrorAlert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/**
* Enhanced error alert component for displaying OpenAI API errors
*
* Provides specialized UI feedback for different error types including
* quota exhaustion, rate limiting, and API errors.
*
* Related to GitHub issue #362 - improves user experience by showing
* clear, actionable error messages instead of generic failures.
*/

import React from 'react';
import { Alert, AlertDescription } from './Alert';
import { EnhancedError, getDisplayErrorMessage, getErrorSeverity, getErrorAction } from '../../services/knowledgeBaseErrorHandler';

interface ErrorAlertProps {
error: EnhancedError | null;
onDismiss?: () => void;
className?: string;
}

/**
* Validate error object structure and properties
*/
function isValidError(error: any): error is EnhancedError {
if (!error || typeof error !== 'object') return false;

// Check that it has basic Error properties
if (typeof error.message !== 'string') return false;

// If it claims to be an OpenAI error, validate the structure
if (error.isOpenAIError === true) {
if (!error.errorDetails || typeof error.errorDetails !== 'object') return false;

const { error_type, message, error: errorField } = error.errorDetails;
if (typeof error_type !== 'string' || typeof message !== 'string') return false;
}

// If statusCode is present, it should be a number
if (error.statusCode !== undefined && typeof error.statusCode !== 'number') return false;

return true;
}

export const ErrorAlert: React.FC<ErrorAlertProps> = ({ error, onDismiss, className = '' }) => {
if (!error) return null;

// Validate error object structure
if (!isValidError(error)) {
console.warn('Invalid error object passed to ErrorAlert:', error);
// Create a fallback error object
const fallbackError: EnhancedError = Object.assign(new Error('Invalid error object received'), {
errorDetails: {
error: 'validation_error',
message: 'An error occurred but the error details could not be parsed properly.',
error_type: 'api_error' as const
}
});
error = fallbackError;
}

const severity = getErrorSeverity(error);
const displayMessage = getDisplayErrorMessage(error);
const suggestedAction = getErrorAction(error);

// Determine alert styling based on severity
const alertVariant = severity === 'error' ? 'destructive' : 'default';

// Special styling for OpenAI errors
const isOpenAIError = error.isOpenAIError;

return (
<Alert variant={alertVariant} className={`mb-4 ${className}`}>
<div className="flex items-start justify-between">
<div className="flex-1">
{/* Error icon based on type */}
<div className="flex items-center gap-2 mb-2">
{isOpenAIError ? (
<span className="text-lg">⚠️</span>
) : (
<span className="text-lg">❌</span>
)}
<span className="font-semibold">
{isOpenAIError ? 'OpenAI API Error' : 'Error'}
</span>
</div>

{/* Main error message */}
<AlertDescription className="text-sm mb-2">
{displayMessage}
</AlertDescription>

{/* Suggested action for OpenAI errors */}
{suggestedAction && (
<div className="mt-2 p-2 bg-blue-50 border-l-4 border-blue-400 rounded-r">
<p className="text-sm font-medium text-blue-800">
πŸ’‘ Suggested action:
</p>
<p className="text-sm text-blue-700 mt-1">
{suggestedAction}
</p>
</div>
)}

{/* Token usage info for quota errors */}
{error.errorDetails?.tokens_used && (
<div className="mt-2 text-xs text-gray-600">
Tokens used: {error.errorDetails.tokens_used.toLocaleString()}
</div>
)}
</div>

{/* Dismiss button */}
{onDismiss && (
<button
onClick={onDismiss}
className="ml-4 text-gray-400 hover:text-gray-600 focus:outline-none"
aria-label="Dismiss error"
>
<span className="text-lg">Γ—</span>
</button>
)}
</div>
</Alert>
);
};

/**
* Hook for handling knowledge base operation errors
*
* Usage example:
* ```tsx
* const { error, setError, clearError } = useErrorHandler();
*
* const handleSearch = async () => {
* try {
* await knowledgeBaseService.searchKnowledgeBase(query);
* } catch (err) {
* setError(err as EnhancedError);
* }
* };
*
* return (
* <>
* <ErrorAlert error={error} onDismiss={clearError} />
* <YourComponentContent />
* </>
* );
* ```
*/
export function useErrorHandler() {
const [error, setError] = React.useState<EnhancedError | null>(null);

const clearError = React.useCallback(() => {
setError(null);
}, []);

return {
error,
setError,
clearError
};
}
22 changes: 18 additions & 4 deletions archon-ui-main/src/pages/KnowledgeBasePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { GroupCreationModal } from '../components/knowledge-base/GroupCreationMo
import { AddKnowledgeModal } from '../components/knowledge-base/AddKnowledgeModal';
import { CrawlingTab } from '../components/knowledge-base/CrawlingTab';
import { DocumentBrowser } from '../components/knowledge-base/DocumentBrowser';
import { parseKnowledgeBaseError, getDisplayErrorMessage, getErrorAction } from '../services/knowledgeBaseErrorHandler';

interface GroupedKnowledgeItem {
id: string;
Expand Down Expand Up @@ -72,7 +73,11 @@ export const KnowledgeBasePage = () => {
setTotalItems(response.total);
} catch (error) {
console.error('Failed to load knowledge items:', error);
showToast('Failed to load knowledge items', 'error');

// Parse the error using enhanced error handler
const enhancedError = parseKnowledgeBaseError(error);
const displayMessage = getDisplayErrorMessage(enhancedError);
showToast(displayMessage, 'error');
setKnowledgeItems([]);
} finally {
setLoading(false);
Expand Down Expand Up @@ -409,7 +414,17 @@ export const KnowledgeBasePage = () => {
}
} catch (error) {
console.error('Failed to refresh knowledge item:', error);
showToast('Failed to refresh knowledge item', 'error');

// Parse the error using enhanced error handler
const enhancedError = parseKnowledgeBaseError(error);
const displayMessage = getDisplayErrorMessage(enhancedError);
const suggestedAction = getErrorAction(enhancedError);

const fullMessage = suggestedAction
? `${displayMessage} ${suggestedAction}`
: displayMessage;

showToast(fullMessage, 'error');
}
};

Expand Down Expand Up @@ -801,7 +816,6 @@ export const KnowledgeBasePage = () => {
}}
/>
)}

{/* Document Browser Modal */}
{isDocumentBrowserOpen && documentBrowserSourceId && (
<DocumentBrowser
Expand All @@ -815,4 +829,4 @@ export const KnowledgeBasePage = () => {
)}
</div>
);
};
};
Loading