Fix duplicate messages after entering a running chain
When the chat is opened while a chain is already streaming, the recovery poll (_streamingPollInterval) is started. Its forced pollHistory(true) renders the DB messages while the live SSE bubbles render them too — the live bubbles never advance lastKnownMessageId, so the poll re-fetches the same assistant message and renders a second bubble. Make live SSE and the recovery poll mutually exclusive: - Stop a lingering recovery poll at the start of a real live stream so the SSE renders alone. - Re-ensure the regular (isStreaming-guarded) history polling idempotently in the finally block, so it is not left off after entering a running chain. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
f2fd493e5f
commit
cf4238859e
1 file changed
+14
@@ -279,6 +279,15 @@ async function _runStream(fetchPromise) {
|
|||||||
stopBtn.hidden = false;
|
stopBtn.hidden = false;
|
||||||
isStreaming = true;
|
isStreaming = true;
|
||||||
_abortController = new AbortController();
|
_abortController = new AbortController();
|
||||||
|
// Eine Live-SSE-Antwort rendert ALLEIN. Einen evtl. noch laufenden Recovery-Poll
|
||||||
|
// (_streamingPollInterval – gestartet beim Betreten des Chats WAEHREND eine Chain
|
||||||
|
// lief) hier stoppen. Sonst rendert dessen pollHistory(true) dieselben DB-Nachrichten
|
||||||
|
// ein zweites Mal NEBEN den Live-Bubbles (die lastKnownMessageId nicht vorruecken)
|
||||||
|
// => Doppel-Nachrichten nach Eintritt in eine laufende Chain.
|
||||||
|
if (_streamingPollInterval) {
|
||||||
|
clearInterval(_streamingPollInterval);
|
||||||
|
_streamingPollInterval = null;
|
||||||
|
}
|
||||||
_currentToolBox = null;
|
_currentToolBox = null;
|
||||||
_chatAbandoned = false;
|
_chatAbandoned = false;
|
||||||
_stopClickCount = 0;
|
_stopClickCount = 0;
|
||||||
@@ -345,6 +354,11 @@ async function _runStream(fetchPromise) {
|
|||||||
stopBtn.title = 'Antwort abbrechen';
|
stopBtn.title = 'Antwort abbrechen';
|
||||||
isStreaming = false;
|
isStreaming = false;
|
||||||
_abortController = null;
|
_abortController = null;
|
||||||
|
// Regulaeres History-Polling idempotent wieder sicherstellen: Falls beim Eintritt
|
||||||
|
// in eine laufende Chain auf den Recovery-Poll umgeschaltet (und History-Polling
|
||||||
|
// gestoppt) wurde, ist es nach dem Live-Stream sonst aus. startHistoryPolling()
|
||||||
|
// hat selbst einen Guard (if (historyPollInterval) return) => kein Doppel-Intervall.
|
||||||
|
startHistoryPolling();
|
||||||
// Steering-Hinweis zurücksetzen (Eingabe ist wieder normales Senden)
|
// Steering-Hinweis zurücksetzen (Eingabe ist wieder normales Senden)
|
||||||
if (_steerInputEl) {
|
if (_steerInputEl) {
|
||||||
_steerInputEl.placeholder = _prevPlaceholder;
|
_steerInputEl.placeholder = _prevPlaceholder;
|
||||||
|
|||||||
Reference in new issue
Block a user