fix: Agent bricht bei Page-Refresh nicht mehr ab + SSE-Writes crash-sicher
Ursache: WriteSseEvent in ProcessStream warf OperationCanceledException bei Client-Disconnect (Page-Refresh) → sseCt war gelinkt mit dem ASP.NET cancellationToken → Exception wurde im catch-Block als 'stopped' behandelt → Agent brach ab obwohl nur der Browser refreshed wurde. Fixes: - ProcessStream: Alle WriteSseEvent durch TryWriteSse ersetzt SSE-Writes bei Client-Disconnect werden jetzt zu stillen No-Ops statt den gesamten Agent-Flow per Exception zu killen - catch-Blöcke: OperationCanceledException nur bei workCt/hardCt als 'stopped' behandeln, neuer catch für Client-Disconnect als 'client_disconnected' (Fallback, sollte nicht mehr auftreten) - done-Event nach Stop: sseCt → CancellationToken.None damit das done-Event trotz gecancelltem sseCt noch gesendet wird - Frontend: done-Handler rendert Chain-Badge direkt im apiGetChain- Callback statt Race-Condition mit finally-Block - Frontend: 'stopped' Badge wieder angezeigt (war nur fälschlich bei Page-Refresh, jetzt korrekt nur bei echtem Stop)
This commit is contained in:
1 parent
b1d449b997
commit
6499864f13
2 files changed
+55
-13
No files matched your search
+10
-4
@@ -121,11 +121,13 @@ function handleStreamEvent(eventType, data) {
|
||||
if (data.model) {
|
||||
_lastDoneChainData = data;
|
||||
} else if (data.chainId) {
|
||||
// Fallback: Chain-Daten vom Server nachladen und Badge direkt rendern
|
||||
// (async – _lastDoneChainData wäre im finally schon gelesen)
|
||||
apiGetChain(data.chainId).then(chain => {
|
||||
if (chain) _lastDoneChainData = chain;
|
||||
if (chain) addChainMetaBubble(chain, false);
|
||||
}).catch(() => {});
|
||||
}
|
||||
setMeta('Bereit');
|
||||
setMeta(data.stopReason === 'stopped' ? 'Gestoppt' : 'Bereit');
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -238,8 +240,7 @@ async function _runStream(fetchPromise) {
|
||||
if (_chatAbandoned) return;
|
||||
endStreamBubble();
|
||||
if (e.name === 'AbortError') {
|
||||
setMeta('Abgebrochen');
|
||||
await new Promise(r => setTimeout(r, 500));
|
||||
setMeta('Gestoppt');
|
||||
} else {
|
||||
try {
|
||||
const status = await apiIsStreaming(sid);
|
||||
@@ -261,6 +262,11 @@ async function _runStream(fetchPromise) {
|
||||
stopBtn.title = 'Antwort abbrechen';
|
||||
isStreaming = false;
|
||||
_abortController = null;
|
||||
// Meta zurücksetzen falls kein done-Event kam (z.B. nach Stop)
|
||||
var metaEl = $('#meta');
|
||||
if (metaEl && metaEl.textContent.includes('Streaming')) {
|
||||
setMeta(_stopClickCount > 0 ? 'Gestoppt' : 'Bereit');
|
||||
}
|
||||
}
|
||||
endStreamBubble();
|
||||
removeStreamedElements();
|
||||
|
||||
Reference in new issue
Block a user