fix(chat): Web-Search-Streaming – Text-Bubbles nach Search in gleicher Bubble fortsetzen

- chat.js: _afterWebSearch Flag trackt ob gerade eine Web-Search beendet wurde
  - text_start nach Web-Search: resumeStreamBubble() statt neue Bubble
  - web_search_start: Bubble NICHT beenden (bleibt finalisiert im DOM)
  - web_search_end: setzt _afterWebSearch=true
  - Flag wird bei tool_start, review_start, finalizer_start, error, done zurückgesetzt
- ui.js: Neue resumeStreamBubble() Funktion
  - _lastStreamDiv/_lastStreamText speichern letzte finalisierte Bubble
  - resumeStreamBubble() reaktiviert die letzte Bubble zum Weiter-Streamen
  - Verhindert separate Message-Blöcke bei mehrfachen Web-Searches
This commit is contained in:
Meleki committed 2026-03-07 09:48:14 +01:00
1 parent 4bec740765
commit 116f21105c
2 files changed
+34 -3

No files matched your search

+16 -3
View File
@@ -139,6 +139,7 @@ async function sendMessage() {
let fullText = '';
let currentToolBox = null;
let _afterWebSearch = false; // true wenn gerade eine Web-Search beendet wurde
_chatAbandoned = false;
@@ -166,8 +167,14 @@ async function sendMessage() {
switch (eventType) {
case 'text_start':
endStreamBubble();
startStreamBubble();
if (_afterWebSearch) {
// Nach Web-Search: letzte Bubble wiederverwenden statt neue
_afterWebSearch = false;
resumeStreamBubble();
} else {
endStreamBubble();
startStreamBubble();
}
break;
case 'text_delta':
@@ -180,6 +187,7 @@ async function sendMessage() {
break;
case 'tool_start':
_afterWebSearch = false;
endStreamBubble();
if (isToolVisible(data.name)) {
currentToolBox = addToolBoxLoading(data.name);
@@ -196,7 +204,7 @@ async function sendMessage() {
break;
case 'web_search_start':
endStreamBubble();
// Bubble NICHT beenden – Text wird nach Search fortgesetzt
currentToolBox = addToolBoxLoading('web_search');
break;
@@ -205,9 +213,11 @@ async function sendMessage() {
finishToolBox(currentToolBox, { name: 'web_search', result: 'Suche abgeschlossen', isError: false });
}
currentToolBox = null;
_afterWebSearch = true;
break;
case 'review_start':
_afterWebSearch = false;
endStreamBubble();
addReviewBubble('start', data);
break;
@@ -229,6 +239,7 @@ async function sendMessage() {
break;
case 'finalizer_start':
_afterWebSearch = false;
endStreamBubble();
addReviewBubble('start', data, 'finalizer');
break;
@@ -246,11 +257,13 @@ async function sendMessage() {
break;
case 'error':
_afterWebSearch = false;
endStreamBubble();
addErrorBubble(data.error, true);
break;
case 'done':
_afterWebSearch = false;
endStreamBubble();
if (data.stopReason === 'max_tokens') {
addWarningBubble('Antwort wurde abgeschnitten (max_tokens erreicht). Bitte frage nach dem Rest.', true);