u
This commit is contained in:
@@ -607,44 +607,19 @@ const actions = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* SSE Event: {"state":"reasoning"}
|
* 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() {
|
applyStreamReasoningState() {
|
||||||
chatAutomat.setState((prev) => {
|
chatAutomat.setState((prev) => {
|
||||||
const turns = prev.activeTurns ? [...prev.activeTurns] : [];
|
const turns = prev.activeTurns ? [...prev.activeTurns] : [];
|
||||||
if (turns.length === 0) {
|
if (turns.length === 0) return { streamPhase: 'thinking' };
|
||||||
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' };
|
|
||||||
}
|
|
||||||
const lastIdx = turns.length - 1;
|
const lastIdx = turns.length - 1;
|
||||||
const lastTurn = { ...turns[lastIdx] };
|
const lastTurn = { ...turns[lastIdx] };
|
||||||
const existingR = lastTurn.reasonings || [];
|
// Seal any existing reasoning that has text
|
||||||
const lastR = existingR[existingR.length - 1];
|
lastTurn.reasonings = (lastTurn.reasonings || [])
|
||||||
|
|
||||||
// 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
|
|
||||||
.filter((r) => r.text && r.text.trim())
|
.filter((r) => r.text && r.text.trim())
|
||||||
.map((r) => ({ ...r, sealed: true }));
|
.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;
|
turns[lastIdx] = lastTurn;
|
||||||
return { activeTurns: turns, streamPhase: 'thinking' };
|
return { activeTurns: turns, streamPhase: 'thinking' };
|
||||||
});
|
});
|
||||||
@@ -652,12 +627,11 @@ const actions = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* SSE Event: event: reasoning, data: {"text":"..."}
|
* SSE Event: event: reasoning, data: {"text":"..."}
|
||||||
* Adds brain icon right of handshake icon (if not added yet).
|
* Adds brain icon with text as chunks stream in.
|
||||||
* Tooltip shows reasoning text. Updates as chunks stream in.
|
|
||||||
*/
|
*/
|
||||||
applyStreamReasoning(data) {
|
applyStreamReasoning(data) {
|
||||||
const text = typeof data?.text === 'string' ? data.text : (typeof data === 'string' ? data : '');
|
const text = typeof data?.text === 'string' ? data.text : (typeof data === 'string' ? data : '');
|
||||||
if (!text) return;
|
if (!text || !text.trim()) return;
|
||||||
chatAutomat.setState((prev) => {
|
chatAutomat.setState((prev) => {
|
||||||
const turns = prev.activeTurns ? [...prev.activeTurns] : [];
|
const turns = prev.activeTurns ? [...prev.activeTurns] : [];
|
||||||
if (turns.length === 0) {
|
if (turns.length === 0) {
|
||||||
@@ -674,7 +648,7 @@ const actions = {
|
|||||||
}
|
}
|
||||||
const lastIdx = turns.length - 1;
|
const lastIdx = turns.length - 1;
|
||||||
const lastTurn = { ...turns[lastIdx] };
|
const lastTurn = { ...turns[lastIdx] };
|
||||||
const rList = lastTurn.reasonings ? [...lastTurn.reasonings] : [];
|
const rList = (lastTurn.reasonings || []).map((r) => ({ ...r }));
|
||||||
let unsealedIdx = -1;
|
let unsealedIdx = -1;
|
||||||
for (let i = rList.length - 1; i >= 0; i--) {
|
for (let i = rList.length - 1; i >= 0; i--) {
|
||||||
if (!rList[i].sealed) {
|
if (!rList[i].sealed) {
|
||||||
@@ -683,7 +657,7 @@ const actions = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (unsealedIdx >= 0) {
|
if (unsealedIdx >= 0) {
|
||||||
rList[unsealedIdx] = { ...rList[unsealedIdx], text };
|
rList[unsealedIdx].text = text;
|
||||||
} else {
|
} else {
|
||||||
rList.push({ id: `r-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`, text, sealed: false });
|
rList.push({ id: `r-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`, text, sealed: false });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ function HandshakeIconView({ state }) {
|
|||||||
|
|
||||||
function BrainIconView({ reasoning }) {
|
function BrainIconView({ reasoning }) {
|
||||||
const tooltipContent = reasoning?.text?.trim() || '';
|
const tooltipContent = reasoning?.text?.trim() || '';
|
||||||
if (!tooltipContent && reasoning?.sealed) return null;
|
if (!tooltipContent) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ClickTooltip
|
<ClickTooltip
|
||||||
@@ -176,7 +176,7 @@ function BrainIconView({ reasoning }) {
|
|||||||
lineHeight: 1.45,
|
lineHeight: 1.45,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{tooltipContent || 'Wird überlegt…'}
|
{tooltipContent}
|
||||||
</Box>
|
</Box>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -287,7 +287,7 @@ export function TurnRow({ turn, isLive = false }) {
|
|||||||
|
|
||||||
const hasReasonings = Boolean(
|
const hasReasonings = Boolean(
|
||||||
turn.reasonings &&
|
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 hasTools = Boolean(turn.tools && turn.tools.length > 0);
|
||||||
const hasContent = Boolean(turn.content);
|
const hasContent = Boolean(turn.content);
|
||||||
|
|||||||
Reference in New Issue
Block a user