Skip to content

Commit 5c9a5a0

Browse files
committed
fix(ui): add file
1 parent 6235576 commit 5c9a5a0

1 file changed

Lines changed: 60 additions & 9 deletions

File tree

apps/sim/app/workspace/[workspaceId]/home/components/message-content/message-content.tsx

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,56 @@ interface StoppedSegment {
4444

4545
type MessageSegment = TextSegment | AgentGroupSegment | OptionsSegment | StoppedSegment
4646

47+
function getAgentGroupActivityKey(items: AgentGroupItem[]): string {
48+
return items
49+
.map((item) => {
50+
if (item.type === 'text' || item.type === 'thinking') {
51+
return `${item.type}:${item.content.length}`
52+
}
53+
if (item.type === 'tool') {
54+
return [
55+
'tool',
56+
item.data.id,
57+
item.data.status,
58+
item.data.displayTitle,
59+
item.data.streamingArgs?.length ?? 0,
60+
].join(':')
61+
}
62+
return [
63+
'agent',
64+
item.group.id,
65+
item.group.isDelegating ? 1 : 0,
66+
item.group.isOpen ? 1 : 0,
67+
getAgentGroupActivityKey(item.group.items),
68+
].join(':')
69+
})
70+
.join('|')
71+
}
72+
73+
/**
74+
* Compact identity for what the transcript is visibly rendering. Main-lane
75+
* reasoning and other suppressed blocks intentionally do not affect it, while
76+
* activity in every nested/parallel lane does.
77+
*/
78+
function getVisibleStreamActivityKey(segments: MessageSegment[]): string {
79+
return segments
80+
.map((segment) => {
81+
if (segment.type === 'text') return `text:${segment.id}:${segment.content.length}`
82+
if (segment.type === 'options') {
83+
return `options:${segment.items.map((item) => `${item.id}:${item.label.length}`).join(',')}`
84+
}
85+
if (segment.type === 'stopped') return 'stopped'
86+
return [
87+
'agent',
88+
segment.id,
89+
segment.isDelegating ? 1 : 0,
90+
segment.isOpen ? 1 : 0,
91+
getAgentGroupActivityKey(segment.items),
92+
].join(':')
93+
})
94+
.join('||')
95+
}
96+
4797
const SUBAGENT_KEYS = new Set(Object.keys(SUBAGENT_LABELS))
4898

4999
/**
@@ -799,7 +849,15 @@ function MessageContentInner({
799849
}, [])
800850
const [isStreamIdle, setIsStreamIdle] = useState(false)
801851

802-
// Every rendered stream snapshot restarts the quiet-period clock. A layout
852+
const segments: MessageSegment[] =
853+
parsed.length > 0
854+
? parsed
855+
: fallbackContent?.trim()
856+
? [{ type: 'text' as const, id: 'text-fallback', content: fallbackContent }]
857+
: []
858+
const visibleStreamActivityKey = getVisibleStreamActivityKey(segments)
859+
860+
// Every visible stream update restarts the quiet-period clock. A layout
803861
// effect clears an already-visible indicator before paint, so a chunk from
804862
// any parallel lane hides the one turn-level loader without a stale flash.
805863
useLayoutEffect(() => {
@@ -811,14 +869,7 @@ function MessageContentInner({
811869
setIsStreamIdle(false)
812870
const timeout = setTimeout(() => setIsStreamIdle(true), STREAM_IDLE_DELAY_MS)
813871
return () => clearTimeout(timeout)
814-
}, [blocks, fallbackContent, isStreaming])
815-
816-
const segments: MessageSegment[] =
817-
parsed.length > 0
818-
? parsed
819-
: fallbackContent?.trim()
820-
? [{ type: 'text' as const, id: 'text-fallback', content: fallbackContent }]
821-
: []
872+
}, [visibleStreamActivityKey, isStreaming])
822873

823874
const lastSegment = segments[segments.length - 1]
824875
const hasTrailingTextSegment = lastSegment?.type === 'text'

0 commit comments

Comments
 (0)