diff --git a/ui-tui/src/app/turnController.ts b/ui-tui/src/app/turnController.ts index ce6cc60006..e676fbd33b 100644 --- a/ui-tui/src/app/turnController.ts +++ b/ui-tui/src/app/turnController.ts @@ -88,6 +88,7 @@ class TurnController { turnTools: string[] = [] private activeTools: ActiveTool[] = [] + private reasoningSegmentIndex: null | number = null private activityId = 0 private reasoningStreamingTimer: Timer = null private reasoningTimer: Timer = null @@ -191,6 +192,33 @@ class TurnController { }) } + private syncReasoningSegment() { + const thinking = this.reasoningText.trim() + + if (!thinking) { + return + } + + const msg: Msg = { + kind: 'trail', + role: 'system', + text: '', + thinking, + thinkingTokens: estimateTokensRough(thinking), + toolTokens: this.toolTokenAcc || undefined, + ...(this.pendingSegmentTools.length && { tools: this.pendingSegmentTools }) + } + + if (this.reasoningSegmentIndex === null) { + this.reasoningSegmentIndex = this.segmentMessages.length + this.segmentMessages = [...this.segmentMessages, msg] + } else { + this.segmentMessages = this.segmentMessages.map((item, i) => (i === this.reasoningSegmentIndex ? msg : item)) + } + + patchTurnState({ streamSegments: this.segmentMessages }) + } + flushStreamingSegment() { const raw = this.bufRef.trimStart() const split = raw ? (hasReasoningTag(raw) ? splitReasoning(raw) : { reasoning: '', text: raw }) : { reasoning: '', text: '' } @@ -331,7 +359,8 @@ class TurnController { toolTokens: savedToolTokens || undefined, ...(tools.length && { tools }) } - const finalMessages = hasDetails(finalDetails) ? [...segments, finalDetails] : [...segments] + const hasReasoningSegment = this.reasoningSegmentIndex !== null + const finalMessages = hasDetails(finalDetails) && !hasReasoningSegment ? [...segments, finalDetails] : [...segments] if (finalText) { finalMessages.push({ role: 'assistant', text: finalText }) @@ -391,6 +420,7 @@ class TurnController { this.reasoningText = incoming this.scheduleReasoning() + this.syncReasoningSegment() this.pulseReasoningStreaming() } @@ -401,6 +431,7 @@ class TurnController { this.reasoningText += text this.scheduleReasoning() + this.syncReasoningSegment() this.pulseReasoningStreaming() } @@ -485,6 +516,7 @@ class TurnController { this.lastStatusNote = '' this.pendingSegmentTools = [] this.protocolWarned = false + this.reasoningSegmentIndex = null this.segmentMessages = [] this.turnTools = [] this.toolTokenAcc = 0 diff --git a/ui-tui/src/components/appLayout.tsx b/ui-tui/src/components/appLayout.tsx index c4739c0555..744f6e73c9 100644 --- a/ui-tui/src/components/appLayout.tsx +++ b/ui-tui/src/components/appLayout.tsx @@ -18,7 +18,6 @@ import { Banner, Panel, SessionPanel } from './branding.js' import { MessageLine } from './messageLine.js' import { QueuedMessages } from './queuedMessages.js' import { TextInput } from './textInput.js' -import { ToolTrail } from './thinking.js' const StreamingAssistant = memo(function StreamingAssistant({ busy, @@ -36,28 +35,6 @@ const StreamingAssistant = memo(function StreamingAssistant({ return ( <> - {progress.showProgressArea && ( - - - - )} - {progress.streamSegments.map((msg, i) => (