From 96f8da8c649493a58075c972b2be34dc88a4e307 Mon Sep 17 00:00:00 2001 From: seb Date: Mon, 5 Oct 2026 23:59:41 +0200 Subject: [PATCH] u --- src/automats/chatAutomat.js | 44 ++++++---------------------- src/components/chat/ChatFlowList.jsx | 6 ++-- 2 files changed, 12 insertions(+), 38 deletions(-) diff --git a/src/automats/chatAutomat.js b/src/automats/chatAutomat.js index 6cb09ae..8a0761b 100644 --- a/src/automats/chatAutomat.js +++ b/src/automats/chatAutomat.js @@ -607,44 +607,19 @@ const actions = { /** * SSE Event: {"state":"reasoning"} - * Prepares for reasoning in current turn. Any previous unsealed reasoning is sealed. + * Sets stream phase to thinking and seals any previous reasoning. + * Does NOT create an empty icon — the icon is only created when reasoning text arrives. */ applyStreamReasoningState() { chatAutomat.setState((prev) => { const turns = prev.activeTurns ? [...prev.activeTurns] : []; - if (turns.length === 0) { - turns.push({ - id: `turn-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`, - handshake: 'green', - reasonings: [{ id: `r-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`, text: '', sealed: false }], - tools: [], - usage: null, - content: '', - sealed: false, - }); - return { activeTurns: turns, streamPhase: 'thinking' }; - } + if (turns.length === 0) return { streamPhase: 'thinking' }; const lastIdx = turns.length - 1; const lastTurn = { ...turns[lastIdx] }; - const existingR = lastTurn.reasonings || []; - const lastR = existingR[existingR.length - 1]; - - // If the last reasoning is already unsealed and waiting for text, do not create a duplicate - if (lastR && !lastR.sealed && !lastR.text?.trim()) { - return { streamPhase: 'thinking' }; - } - - // Filter out empty reasonings and seal existing ones - const nextR = existingR + // Seal any existing reasoning that has text + lastTurn.reasonings = (lastTurn.reasonings || []) .filter((r) => r.text && r.text.trim()) .map((r) => ({ ...r, sealed: true })); - - nextR.push({ - id: `r-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`, - text: '', - sealed: false, - }); - lastTurn.reasonings = nextR; turns[lastIdx] = lastTurn; return { activeTurns: turns, streamPhase: 'thinking' }; }); @@ -652,12 +627,11 @@ const actions = { /** * SSE Event: event: reasoning, data: {"text":"..."} - * Adds brain icon right of handshake icon (if not added yet). - * Tooltip shows reasoning text. Updates as chunks stream in. + * Adds brain icon with text as chunks stream in. */ applyStreamReasoning(data) { const text = typeof data?.text === 'string' ? data.text : (typeof data === 'string' ? data : ''); - if (!text) return; + if (!text || !text.trim()) return; chatAutomat.setState((prev) => { const turns = prev.activeTurns ? [...prev.activeTurns] : []; if (turns.length === 0) { @@ -674,7 +648,7 @@ const actions = { } const lastIdx = turns.length - 1; const lastTurn = { ...turns[lastIdx] }; - const rList = lastTurn.reasonings ? [...lastTurn.reasonings] : []; + const rList = (lastTurn.reasonings || []).map((r) => ({ ...r })); let unsealedIdx = -1; for (let i = rList.length - 1; i >= 0; i--) { if (!rList[i].sealed) { @@ -683,7 +657,7 @@ const actions = { } } if (unsealedIdx >= 0) { - rList[unsealedIdx] = { ...rList[unsealedIdx], text }; + rList[unsealedIdx].text = text; } else { rList.push({ id: `r-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`, text, sealed: false }); } diff --git a/src/components/chat/ChatFlowList.jsx b/src/components/chat/ChatFlowList.jsx index bf1a2a6..f3fda41 100644 --- a/src/components/chat/ChatFlowList.jsx +++ b/src/components/chat/ChatFlowList.jsx @@ -160,7 +160,7 @@ function HandshakeIconView({ state }) { function BrainIconView({ reasoning }) { const tooltipContent = reasoning?.text?.trim() || ''; - if (!tooltipContent && reasoning?.sealed) return null; + if (!tooltipContent) return null; return ( - {tooltipContent || 'Wird überlegt…'} + {tooltipContent} } > @@ -287,7 +287,7 @@ export function TurnRow({ turn, isLive = false }) { const hasReasonings = Boolean( turn.reasonings && - turn.reasonings.some((r) => !r.sealed || Boolean(r.text && r.text.trim())) + turn.reasonings.some((r) => Boolean(r.text && r.text.trim())) ); const hasTools = Boolean(turn.tools && turn.tools.length > 0); const hasContent = Boolean(turn.content);