Revert "fix: resolve chat conversation hanging and stream interruption issues (#1971)"
This reverts commit e68593f22d.
This commit is contained in:
@@ -13,7 +13,6 @@ import { createSummary } from '~/lib/.server/llm/create-summary';
|
||||
import { extractPropertiesFromMessage } from '~/lib/.server/llm/utils';
|
||||
import type { DesignScheme } from '~/types/design-scheme';
|
||||
import { MCPService } from '~/lib/services/mcpService';
|
||||
import { StreamRecoveryManager } from '~/lib/.server/llm/stream-recovery';
|
||||
|
||||
export async function action(args: ActionFunctionArgs) {
|
||||
return chatAction(args);
|
||||
@@ -75,22 +74,6 @@ async function chatAction({ context, request }: ActionFunctionArgs) {
|
||||
const encoder: TextEncoder = new TextEncoder();
|
||||
let progressCounter: number = 1;
|
||||
|
||||
// Initialize stream recovery manager
|
||||
const recovery = new StreamRecoveryManager({
|
||||
maxRetries: 3,
|
||||
retryDelay: 2000,
|
||||
timeout: 45000, // 45 seconds timeout
|
||||
onTimeout: () => {
|
||||
logger.warn('Stream timeout detected - attempting recovery');
|
||||
},
|
||||
onRetry: (attempt) => {
|
||||
logger.info(`Stream recovery attempt ${attempt}`);
|
||||
},
|
||||
onError: (error) => {
|
||||
logger.error('Stream error in recovery:', error);
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
const mcpService = MCPService.getInstance();
|
||||
const totalMessageContent = messages.reduce((acc, message) => acc + message.content, '');
|
||||
@@ -330,77 +313,28 @@ async function chatAction({ context, request }: ActionFunctionArgs) {
|
||||
});
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
recovery.startMonitoring();
|
||||
for await (const part of result.fullStream) {
|
||||
if (part.type === 'error') {
|
||||
const error: any = part.error;
|
||||
logger.error('Streaming error:', error);
|
||||
|
||||
let lastActivityTime = Date.now();
|
||||
const activityCheckInterval = 5000; // Check every 5 seconds
|
||||
|
||||
// Set up activity monitoring
|
||||
const activityChecker = setInterval(() => {
|
||||
const timeSinceLastActivity = Date.now() - lastActivityTime;
|
||||
|
||||
if (timeSinceLastActivity > 30000) {
|
||||
logger.warn(`No stream activity for ${timeSinceLastActivity}ms`);
|
||||
|
||||
// Attempt to recover if stream appears stuck
|
||||
recovery.attemptRecovery();
|
||||
// Enhanced error handling for common streaming issues
|
||||
if (error.message?.includes('Invalid JSON response')) {
|
||||
logger.error('Invalid JSON response detected - likely malformed API response');
|
||||
} else if (error.message?.includes('token')) {
|
||||
logger.error('Token-related error detected - possible token limit exceeded');
|
||||
}
|
||||
}, activityCheckInterval);
|
||||
|
||||
for await (const part of result.fullStream) {
|
||||
// Record activity
|
||||
lastActivityTime = Date.now();
|
||||
recovery.recordActivity();
|
||||
|
||||
if (part.type === 'error') {
|
||||
const error: any = part.error;
|
||||
logger.error('Streaming error:', error);
|
||||
|
||||
// Enhanced error handling for common streaming issues
|
||||
if (error.message?.includes('Invalid JSON response')) {
|
||||
logger.error('Invalid JSON response detected - likely malformed API response');
|
||||
} else if (error.message?.includes('token')) {
|
||||
logger.error('Token-related error detected - possible token limit exceeded');
|
||||
}
|
||||
|
||||
// Attempt recovery for certain errors
|
||||
const canRecover = await recovery.handleError(error);
|
||||
|
||||
if (!canRecover) {
|
||||
clearInterval(activityChecker);
|
||||
recovery.stop();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up
|
||||
clearInterval(activityChecker);
|
||||
recovery.stop();
|
||||
} catch (streamError) {
|
||||
logger.error('Fatal stream error:', streamError);
|
||||
recovery.stop();
|
||||
throw streamError;
|
||||
}
|
||||
})();
|
||||
result.mergeIntoDataStream(dataStream);
|
||||
},
|
||||
onError: (error: any) => {
|
||||
// Stop recovery manager on error
|
||||
recovery.stop();
|
||||
|
||||
// Provide more specific error messages for common issues
|
||||
const errorMessage = error.message || 'Unknown error';
|
||||
|
||||
// Log detailed error for debugging
|
||||
logger.error('Chat API error:', {
|
||||
message: errorMessage,
|
||||
stack: error.stack,
|
||||
code: error.code,
|
||||
});
|
||||
|
||||
if (errorMessage.includes('model') && errorMessage.includes('not found')) {
|
||||
return 'Custom error: Invalid model selected. Please check that the model name is correct and available.';
|
||||
}
|
||||
@@ -426,11 +360,7 @@ async function chatAction({ context, request }: ActionFunctionArgs) {
|
||||
}
|
||||
|
||||
if (errorMessage.includes('network') || errorMessage.includes('timeout')) {
|
||||
return 'Custom error: Network error or timeout. The connection was interrupted. Please try again or switch to a different AI model.';
|
||||
}
|
||||
|
||||
if (errorMessage.includes('stream') || errorMessage.includes('hang')) {
|
||||
return 'Custom error: The conversation stream was interrupted. Please refresh the page and try again.';
|
||||
return 'Custom error: Network error. Please check your internet connection and try again.';
|
||||
}
|
||||
|
||||
return `Custom error: ${errorMessage}`;
|
||||
@@ -473,32 +403,17 @@ async function chatAction({ context, request }: ActionFunctionArgs) {
|
||||
}),
|
||||
);
|
||||
|
||||
// Set up cleanup for recovery manager
|
||||
const cleanupStream = dataStream.pipeThrough(
|
||||
new TransformStream({
|
||||
flush() {
|
||||
recovery.stop();
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
return new Response(cleanupStream, {
|
||||
return new Response(dataStream, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'text/event-stream; charset=utf-8',
|
||||
Connection: 'keep-alive',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Text-Encoding': 'chunked',
|
||||
'X-Accel-Buffering': 'no', // Disable nginx buffering
|
||||
},
|
||||
});
|
||||
} catch (error: any) {
|
||||
logger.error('Fatal error in chat API:', error);
|
||||
|
||||
// Ensure recovery manager is stopped on error
|
||||
if (typeof recovery !== 'undefined') {
|
||||
recovery.stop();
|
||||
}
|
||||
logger.error(error);
|
||||
|
||||
const errorResponse = {
|
||||
error: true,
|
||||
|
||||
Reference in New Issue
Block a user