Fix: Simplified streaming handlers - removed setTimeout batching causing infinite loops
This commit is contained in:
@@ -3386,9 +3386,6 @@ This gives the user a chance to refine requirements before implementation.
|
|||||||
// PROVIDER SWITCH: Use OpenCode Free or Qwen based on provider state
|
// PROVIDER SWITCH: Use OpenCode Free or Qwen based on provider state
|
||||||
const streamStartTime = Date.now(); // Track start time for this request
|
const streamStartTime = Date.now(); // Track start time for this request
|
||||||
let totalCharsReceived = 0; // Track total characters for speed calculation
|
let totalCharsReceived = 0; // Track total characters for speed calculation
|
||||||
let messageUpdateTimeout = null; // Debounce message updates to prevent excessive re-renders
|
|
||||||
let pendingContent = ''; // Buffer for pending content updates
|
|
||||||
let lastProcessedTime = Date.now(); // Track timing for flow control
|
|
||||||
|
|
||||||
const result = provider === 'opencode-free'
|
const result = provider === 'opencode-free'
|
||||||
? await callOpenCodeFree(fullPrompt, freeModel, (chunk) => {
|
? await callOpenCodeFree(fullPrompt, freeModel, (chunk) => {
|
||||||
@@ -3415,10 +3412,6 @@ This gives the user a chance to refine requirements before implementation.
|
|||||||
const elapsedSeconds = (Date.now() - streamStartTime) / 1000;
|
const elapsedSeconds = (Date.now() - streamStartTime) / 1000;
|
||||||
const speed = elapsedSeconds > 0 ? Math.round(totalCharsReceived / elapsedSeconds) : 0;
|
const speed = elapsedSeconds > 0 ? Math.round(totalCharsReceived / elapsedSeconds) : 0;
|
||||||
|
|
||||||
// Flow control - prevent overwhelming the UI
|
|
||||||
const currentTime = Date.now();
|
|
||||||
const timeSinceLastProcess = currentTime - lastProcessedTime;
|
|
||||||
|
|
||||||
// GLOBAL STATS UPDATE (Run for ALL chunks)
|
// GLOBAL STATS UPDATE (Run for ALL chunks)
|
||||||
setThinkingStats(prev => ({
|
setThinkingStats(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
@@ -3435,29 +3428,14 @@ This gives the user a chance to refine requirements before implementation.
|
|||||||
if (isThinkingChunk) {
|
if (isThinkingChunk) {
|
||||||
setThinkingLines(prev => [...prev, ...lines.map(l => l.trim()).filter(l => l && !/^(Let me|Now let me|I'll|I need to|I notice)/i.test(l.trim()))]);
|
setThinkingLines(prev => [...prev, ...lines.map(l => l.trim()).filter(l => l && !/^(Let me|Now let me|I'll|I need to|I notice)/i.test(l.trim()))]);
|
||||||
} else {
|
} else {
|
||||||
// Buffer the content with flow control
|
// Direct message update - simple and stable
|
||||||
pendingContent += cleanChunk;
|
setMessages(prev => {
|
||||||
lastProcessedTime = currentTime;
|
const last = prev[prev.length - 1];
|
||||||
|
if (last && last.role === 'assistant') {
|
||||||
// Clear existing timeout
|
return [...prev.slice(0, -1), { ...last, content: last.content + cleanChunk }];
|
||||||
if (messageUpdateTimeout) {
|
}
|
||||||
clearTimeout(messageUpdateTimeout);
|
return prev;
|
||||||
}
|
});
|
||||||
|
|
||||||
// Use adaptive timing based on content flow
|
|
||||||
const adaptiveDelay = Math.max(8, 16 - Math.min(8, speed / 10)); // Faster streams get less delay
|
|
||||||
|
|
||||||
// Set new timeout to batch updates with flow control
|
|
||||||
messageUpdateTimeout = setTimeout(() => {
|
|
||||||
setMessages(prev => {
|
|
||||||
const last = prev[prev.length - 1];
|
|
||||||
if (last && last.role === 'assistant') {
|
|
||||||
return [...prev.slice(0, -1), { ...last, content: last.content + pendingContent }];
|
|
||||||
}
|
|
||||||
return [...prev, { role: 'assistant', content: pendingContent }];
|
|
||||||
});
|
|
||||||
pendingContent = ''; // Clear the buffer after update
|
|
||||||
}, adaptiveDelay);
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
: await getQwen().sendMessage(fullPrompt, 'qwen-coder-plus', null, (chunk) => {
|
: await getQwen().sendMessage(fullPrompt, 'qwen-coder-plus', null, (chunk) => {
|
||||||
@@ -3497,29 +3475,14 @@ This gives the user a chance to refine requirements before implementation.
|
|||||||
if (isThinkingChunk) {
|
if (isThinkingChunk) {
|
||||||
setThinkingLines(prev => [...prev, ...lines.map(l => l.trim()).filter(l => l && !/^(Let me|Now let me|I'll|I need to|I notice)/i.test(l.trim()))]);
|
setThinkingLines(prev => [...prev, ...lines.map(l => l.trim()).filter(l => l && !/^(Let me|Now let me|I'll|I need to|I notice)/i.test(l.trim()))]);
|
||||||
} else {
|
} else {
|
||||||
// Buffer the content with flow control
|
// Direct message update - simple and stable
|
||||||
pendingContent += cleanChunk;
|
setMessages(prev => {
|
||||||
lastProcessedTime = Date.now();
|
const last = prev[prev.length - 1];
|
||||||
|
if (last && last.role === 'assistant') {
|
||||||
// Clear existing timeout
|
return [...prev.slice(0, -1), { ...last, content: last.content + cleanChunk }];
|
||||||
if (messageUpdateTimeout) {
|
}
|
||||||
clearTimeout(messageUpdateTimeout);
|
return prev;
|
||||||
}
|
});
|
||||||
|
|
||||||
// Use adaptive timing based on content flow
|
|
||||||
const adaptiveDelay = Math.max(8, 16 - Math.min(8, speed / 10)); // Faster streams get less delay
|
|
||||||
|
|
||||||
// Set new timeout to batch updates with flow control
|
|
||||||
messageUpdateTimeout = setTimeout(() => {
|
|
||||||
setMessages(prev => {
|
|
||||||
const last = prev[prev.length - 1];
|
|
||||||
if (last && last.role === 'assistant') {
|
|
||||||
return [...prev.slice(0, -1), { ...last, content: last.content + pendingContent }];
|
|
||||||
}
|
|
||||||
return [...prev, { role: 'assistant', content: pendingContent }];
|
|
||||||
});
|
|
||||||
pendingContent = ''; // Clear the buffer after update
|
|
||||||
}, adaptiveDelay);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user