fix: Streaming-Navigation-Bugs (doppelte Messages, client_disconnected), Tool-Result ohne Truncation
- _chatAbandoned-Flag statt AbortController: Backend-Stream läuft bei Navigation weiter, Frontend ignoriert Events - stopHistoryPolling() während Streaming-Poll aktiv, verhindert parallele Polls - _pollLock in pollHistory() gegen Race-Conditions bei gleichzeitigen Poll-Aufrufen - Tool-Result truncate(300) im Live-Chat entfernt, in History beibehalten - Dashboard Badge-Styling verfeinert
This commit is contained in:
1 parent
6f800e2d50
commit
7c0e5d180a
5 files changed
+30
-7
No files matched your search
@@ -75,10 +75,12 @@
|
||||
|
||||
.badge {
|
||||
padding: var(--badge-padding);
|
||||
background: var(--f1-bg);
|
||||
border: var(--border-width) solid var(--f1-border);
|
||||
background: var(--f2-bg);
|
||||
border: var(--border-width) solid var(--f2-border);
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
font-size: var(--font-size);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
#newAgentCard,
|
||||
|
||||
+8
-1
@@ -33,6 +33,7 @@ let isStreaming = false;
|
||||
let pendingFiles = []; // [{ name, type, base64 }]
|
||||
let pendingRefs = []; // [{ path, from, to }] - Workspace-Dateireferenzen
|
||||
let _lastDoneChainData = null; // Chain-Daten vom letzten done-Event
|
||||
let _chatAbandoned = false; // true wenn User weg-navigiert während Stream läuft
|
||||
|
||||
async function clearChat() {
|
||||
const archive = await apiArchive(getCurrentSessionId());
|
||||
@@ -102,6 +103,8 @@ async function sendMessage() {
|
||||
let fullText = '';
|
||||
let currentToolBox = null;
|
||||
|
||||
_chatAbandoned = false;
|
||||
|
||||
try {
|
||||
const resp = await apiChat(messages, getCurrentSessionId());
|
||||
const reader = resp.body.getReader();
|
||||
@@ -111,7 +114,7 @@ async function sendMessage() {
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
if (done || _chatAbandoned) break;
|
||||
|
||||
buffer += decoder.decode(value, { stream: true });
|
||||
const lines = buffer.split('\n');
|
||||
@@ -184,6 +187,8 @@ async function sendMessage() {
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
// Bei Navigation nichts tun – der neue Page-Init übernimmt
|
||||
if (_chatAbandoned) return;
|
||||
endStreamBubble();
|
||||
// Prüfen ob Backend noch streamt (z.B. bei Netzwerkfehler)
|
||||
try {
|
||||
@@ -197,6 +202,8 @@ async function sendMessage() {
|
||||
} catch (_) {}
|
||||
addErrorBubble('Netzwerk-Fehler: ' + e.message);
|
||||
} finally {
|
||||
// Bei Navigation nichts aufräumen – der neue Page-Init übernimmt
|
||||
if (_chatAbandoned) return;
|
||||
if (!isStreaming || !_streamingPollInterval) {
|
||||
btn.disabled = false;
|
||||
isStreaming = false;
|
||||
|
||||
@@ -143,7 +143,7 @@ async function loadLatestArchive() {
|
||||
if (lastToolBox && !lastToolBox.querySelector('.tool-result')) {
|
||||
const rd = document.createElement('div');
|
||||
rd.className = 'tool-result' + (msg.isError ? ' tool-error' : '');
|
||||
rd.textContent = truncate(msg.content, 300);
|
||||
rd.textContent = truncate(msg.content || '', 300);
|
||||
lastToolBox.appendChild(rd);
|
||||
}
|
||||
continue; // kein separates div
|
||||
@@ -183,6 +183,8 @@ async function loadLatestArchive() {
|
||||
|
||||
// ── Polling ──
|
||||
|
||||
let _pollLock = false;
|
||||
|
||||
function startHistoryPolling(intervalMs = 3000) {
|
||||
if (historyPollInterval) return;
|
||||
historyPollInterval = setInterval(pollHistory, intervalMs);
|
||||
@@ -197,6 +199,8 @@ function stopHistoryPolling() {
|
||||
|
||||
async function pollHistory(force = false) {
|
||||
if (isStreaming && !force) return;
|
||||
if (_pollLock) return;
|
||||
_pollLock = true;
|
||||
|
||||
try {
|
||||
const newMessages = await apiHistoryPoll(getCurrentSessionId(), lastKnownMessageId);
|
||||
@@ -206,5 +210,7 @@ async function pollHistory(force = false) {
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('History poll fehlgeschlagen:', e);
|
||||
} finally {
|
||||
_pollLock = false;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ let _recoveryChainId = null;
|
||||
|
||||
function startStreamingPoll(sessionId, sendBtn, chainId) {
|
||||
_recoveryChainId = chainId;
|
||||
// History-Polling stoppen – Streaming-Poll übernimmt
|
||||
stopHistoryPolling();
|
||||
if (_streamingPollInterval) clearInterval(_streamingPollInterval);
|
||||
_streamingPollInterval = setInterval(async () => {
|
||||
try {
|
||||
@@ -29,6 +31,9 @@ function startStreamingPoll(sessionId, sendBtn, chainId) {
|
||||
}
|
||||
setMeta('Bereit');
|
||||
_recoveryChainId = null;
|
||||
|
||||
// History-Polling wieder starten
|
||||
startHistoryPolling();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Streaming-Poll fehlgeschlagen:', e);
|
||||
@@ -274,6 +279,9 @@ registerPage('chat', {
|
||||
},
|
||||
|
||||
destroy() {
|
||||
// Stream nicht abbrechen (Backend soll weiterlaufen),
|
||||
// aber Frontend-Processing stoppen
|
||||
_chatAbandoned = true;
|
||||
if (this._closeMenu) {
|
||||
document.removeEventListener('click', this._closeMenu);
|
||||
this._closeMenu = null;
|
||||
|
||||
+3
-3
@@ -238,7 +238,7 @@ function renderToolBoxContent(div, name, inputJson, result, isError) {
|
||||
|
||||
const resultDiv = document.createElement('div');
|
||||
resultDiv.className = 'tool-result' + (isError ? ' tool-error' : '');
|
||||
resultDiv.textContent = result ? truncate(result, 300) : '';
|
||||
resultDiv.textContent = result || '';
|
||||
resultDiv.hidden = true;
|
||||
div.appendChild(resultDiv);
|
||||
foldTarget = resultDiv;
|
||||
@@ -340,12 +340,12 @@ function appendToolResult(result, isError) {
|
||||
|
||||
const existing = lastBox.querySelector('.tool-result');
|
||||
if (existing) {
|
||||
existing.textContent = truncate(result, 300);
|
||||
existing.textContent = result || '';
|
||||
if (isError) existing.classList.add('tool-error');
|
||||
} else {
|
||||
const resultDiv = document.createElement('div');
|
||||
resultDiv.className = 'tool-result' + (isError ? ' tool-error' : '');
|
||||
resultDiv.textContent = truncate(result, 300);
|
||||
resultDiv.textContent = result || '';
|
||||
resultDiv.hidden = true;
|
||||
lastBox.appendChild(resultDiv);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user