refactor(tui): render progress in ordered stream timeline

This commit is contained in:
Brooklyn Nicholson
2026-04-26 14:12:43 -05:00
parent 3d21f97422
commit 350ee1bf23
2 changed files with 33 additions and 24 deletions

View File

@@ -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

View File

@@ -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 && (
<Box flexDirection="column" marginBottom={progress.streamSegments.length || progress.showStreamingArea ? 1 : 0}>
<ToolTrail
activity={progress.activity}
busy={busy}
commandOverride={detailsModeCommandOverride}
detailsMode={detailsMode}
outcome={progress.outcome}
reasoning={progress.reasoning}
reasoningActive={progress.reasoningActive}
reasoningStreaming={progress.reasoningStreaming}
reasoningTokens={progress.reasoningTokens}
sections={sections}
subagents={progress.subagents}
t={t}
tools={progress.tools}
toolTokens={progress.toolTokens}
trail={progress.turnTrail}
/>
</Box>
)}
{progress.streamSegments.map((msg, i) => (
<MessageLine
cols={cols}