diff --git a/wwwroot/js/chat.js b/wwwroot/js/chat.js index a5f4d69..e8c5289 100644 --- a/wwwroot/js/chat.js +++ b/wwwroot/js/chat.js @@ -279,6 +279,15 @@ async function _runStream(fetchPromise) { stopBtn.hidden = false; isStreaming = true; _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; _chatAbandoned = false; _stopClickCount = 0; @@ -345,6 +354,11 @@ async function _runStream(fetchPromise) { stopBtn.title = 'Antwort abbrechen'; isStreaming = false; _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) if (_steerInputEl) { _steerInputEl.placeholder = _prevPlaceholder;