@@ -5,7 +5,7 @@ import type { AgentResponseContent, Message, ToolCallInfo } from '@/store/sessio
55import { useSessionStore } from '@/store/session'
66import { aggregateMessages } from '@/store/session/utils/aggregateMessages'
77import { ChevronDown , ChevronRight , FileText , Loader2 } from 'lucide-react'
8- import { useMemo , useState } from 'react'
8+ import { useEffect , useMemo , useState } from 'react'
99import { MarkdownRenderer } from './MarkdownRenderer'
1010
1111export type { Message }
@@ -225,107 +225,83 @@ function ChangedFilesSection({ toolCalls }: { toolCalls: ToolCallInfo[] }) {
225225}
226226
227227function SubagentSection ( { subagent } : { subagent : AgentResponseContent [ 'subagent' ] } ) {
228+ const [ manualToggle , setManualToggle ] = useState < boolean | null > ( null )
229+ const [ loading , setLoading ] = useState ( false )
230+ const [ loadedToolCalls , setLoadedToolCalls ] = useState < ToolCallInfo [ ] | null > ( null )
231+
228232 if ( ! subagent ) return null
229233
230- return (
231- < div className = "bg-[#F9FAFB] dark:bg-[#18181b] border border-[#E5E7EB] dark:border-[#27272a] rounded-lg px-3 py-2" >
232- < div className = "flex gap-2 items-center" >
233- { subagent . status === 'running' && < Loader2 className = "h-3 w-3 animate-spin text-[#6B7280]" /> }
234- < span className = "text-[12px] text-[#6B7280] dark:text-[#71717a] font-mono" >
235- { subagent . type } : { subagent . description }
236- </ span >
237- < StatusPill status = { subagent . status === 'completed' ? 'success' : subagent . status === 'failed' ? 'error' : 'running' } />
238- </ div >
239- </ div >
240- )
241- }
242-
243- function SubtaskRefSection ( { subtaskRef } : { subtaskRef : Record < string , unknown > } ) {
244- const { currentSessionId } = useSessionStore ( )
245- const [ expanded , setExpanded ] = useState ( false )
246- const [ loading , setLoading ] = useState ( false )
247- const [ subagentToolCalls , setSubagentToolCalls ] = useState < ToolCallInfo [ ] | null > ( null )
248- const status = typeof subtaskRef . status === 'string' ? subtaskRef . status : undefined
249- const summary = typeof subtaskRef . summary === 'string' ? subtaskRef . summary : ''
250- const agentType = typeof subtaskRef . agentType === 'string' ? subtaskRef . agentType : 'subagent'
251- const sessionId = typeof subtaskRef . childSessionId === 'string' ? subtaskRef . childSessionId : undefined
252- const pillStatus =
253- status === 'completed' ? 'success' : status === 'failed' ? 'error' : status === 'running' ? 'running' : 'info'
254- const isActive = sessionId && sessionId === currentSessionId
255- const canExpand = ! ! sessionId
256-
257- const handleToggleExpand = async ( ) => {
258- if ( ! sessionId ) return
259- const next = ! expanded
260- setExpanded ( next )
261- if ( next && subagentToolCalls === null ) {
262- setLoading ( true )
263- try {
264- const rawMessages = await sessionService . getMessages ( sessionId )
265- const aggregated = aggregateMessages ( rawMessages )
266- const toolCalls : ToolCallInfo [ ] = [ ]
267- for ( const message of aggregated ) {
268- if ( message . agentContent ?. toolCalls ?. length ) {
269- toolCalls . push ( ...message . agentContent . toolCalls )
234+ const isRunning = subagent . status === 'running'
235+ const expanded = manualToggle !== null ? manualToggle : isRunning
236+ const toolCalls = subagent . toolCalls || loadedToolCalls || [ ]
237+ const hasContent = subagent . output || subagent . thinking || toolCalls . length > 0 || subagent . sessionId
238+
239+ useEffect ( ( ) => {
240+ if ( ! expanded || isRunning || ! subagent . sessionId || loadedToolCalls !== null || ( subagent . toolCalls && subagent . toolCalls . length > 0 ) ) return
241+ let mounted = true
242+ setLoading ( true )
243+ sessionService . getMessages ( subagent . sessionId ) . then ( ( rawMessages ) => {
244+ if ( ! mounted ) return
245+ const aggregated = aggregateMessages ( rawMessages )
246+ const toolCallsMap = new Map < string , ToolCallInfo > ( )
247+ for ( const message of aggregated ) {
248+ if ( message . agentContent ?. toolCalls ?. length ) {
249+ for ( const tc of message . agentContent . toolCalls ) {
250+ if ( ! toolCallsMap . has ( tc . toolCallId ) ) {
251+ toolCallsMap . set ( tc . toolCallId , tc )
252+ }
270253 }
271254 }
272- setSubagentToolCalls ( toolCalls )
273- } finally {
274- setLoading ( false )
275255 }
276- }
277- }
256+ setLoadedToolCalls ( Array . from ( toolCallsMap . values ( ) ) )
257+ } ) . finally ( ( ) => {
258+ if ( mounted ) setLoading ( false )
259+ } )
260+ return ( ) => { mounted = false }
261+ } , [ expanded , isRunning , subagent . sessionId , subagent . toolCalls , loadedToolCalls ] )
278262
279263 return (
280- < div
281- className = { cn (
282- 'bg-[#F9FAFB] dark:bg-[#18181b] border border-[#E5E7EB] dark:border-[#27272a] rounded-lg px-3 py-2 space-y-1' ,
283- isActive ? 'ring-1 ring-[#22C55E]/60' : ''
284- ) }
285- >
286- < div className = "flex gap-2 justify-between items-center" >
264+ < div className = "bg-[#F9FAFB] dark:bg-[#18181b] border border-[#E5E7EB] dark:border-[#27272a] rounded-lg px-3 py-2" >
265+ < button
266+ type = "button"
267+ onClick = { ( ) => setManualToggle ( ! expanded ) }
268+ className = "flex gap-2 justify-between items-center w-full transition-opacity cursor-pointer hover:opacity-80"
269+ >
287270 < div className = "flex gap-2 items-center" >
271+ { isRunning && < Loader2 className = "h-3 w-3 animate-spin text-[#6B7280]" /> }
288272 < span className = "text-[12px] text-[#6B7280] dark:text-[#71717a] font-mono" >
289- Subtask @ { agentType }
273+ { subagent . type } : { subagent . description }
290274 </ span >
291- < StatusPill status = { pillStatus } />
275+ < StatusPill status = { subagent . status === 'completed' ? 'success' : subagent . status === 'failed' ? 'error' : 'running' } />
292276 </ div >
293- < button
294- type = "button"
295- onClick = { ( event ) => {
296- event . stopPropagation ( )
297- void handleToggleExpand ( )
298- } }
299- disabled = { ! canExpand }
300- className = { cn (
301- 'flex items-center gap-1 text-[11px] font-mono px-2 py-1 rounded' ,
302- canExpand
303- ? 'text-[#6B7280] hover:text-[#111827] hover:bg-[#E5E7EB] dark:text-[#71717a] dark:hover:text-[#E5E5E5] dark:hover:bg-[#27272a]'
304- : 'text-[#9CA3AF] dark:text-[#52525b] cursor-not-allowed'
305- ) }
306- >
307- { expanded ? < ChevronDown className = "w-3 h-3" /> : < ChevronRight className = "w-3 h-3" /> }
308- Logs
309- </ button >
310- </ div >
311- { summary && (
312- < div className = "text-[12px] text-[#374151] dark:text-[#d4d4d8] whitespace-pre-wrap" > { summary } </ div >
313- ) }
277+ { hasContent && (
278+ < ChevronDown className = { cn ( 'h-3.5 w-3.5 text-[#6B7280] transition-transform' , expanded && 'rotate-180' ) } />
279+ ) }
280+ </ button >
314281 { expanded && (
315- < div className = "pt-2" >
282+ < div className = "mt-2 space-y-2" >
283+ { ( subagent . output || subagent . thinking ) && (
284+ < >
285+ { subagent . output && (
286+ < pre className = "text-[11px] text-[#374151] dark:text-[#d4d4d8] bg-[#F3F4F6] dark:bg-[#111113] border border-[#E5E7EB] dark:border-[#27272a] rounded-md p-2 overflow-x-auto whitespace-pre-wrap font-mono max-h-[160px] overflow-y-auto" >
287+ { subagent . output }
288+ </ pre >
289+ ) }
290+ { subagent . thinking && (
291+ < pre className = "text-[11px] text-[#6B7280] dark:text-[#a1a1aa] bg-[#F3F4F6] dark:bg-[#111113] border border-[#E5E7EB] dark:border-[#27272a] rounded-md p-2 overflow-x-auto whitespace-pre-wrap font-mono max-h-[120px] overflow-y-auto" >
292+ { subagent . thinking }
293+ </ pre >
294+ ) }
295+ </ >
296+ ) }
316297 { loading && (
317298 < div className = "flex items-center gap-2 text-[11px] text-[#6B7280] dark:text-[#71717a] font-mono" >
318299 < Loader2 className = "w-3 h-3 animate-spin" />
319300 Loading subagent logs...
320301 </ div >
321302 ) }
322- { ! loading && subagentToolCalls && subagentToolCalls . length > 0 && (
323- < ToolCallsList toolCalls = { subagentToolCalls } />
324- ) }
325- { ! loading && subagentToolCalls && subagentToolCalls . length === 0 && (
326- < div className = "text-[11px] text-[#6B7280] dark:text-[#71717a] font-mono" >
327- No tool calls recorded.
328- </ div >
303+ { ! loading && toolCalls . length > 0 && (
304+ < ToolCallsList toolCalls = { toolCalls } />
329305 ) }
330306 </ div >
331307 ) }
@@ -487,11 +463,7 @@ function AgentMessageContent({ message }: { message: Message }) {
487463 }
488464
489465 const { textBefore, toolCalls, textAfter, thinkingContent, todos, subagent, confirmation, question } = agentContent
490- const subtaskRef =
491- message . metadata && typeof message . metadata === 'object' && 'subtaskRef' in message . metadata
492- ? ( message . metadata . subtaskRef as Record < string , unknown > )
493- : null
494- const hasContent = textBefore || toolCalls . length > 0 || textAfter || thinkingContent || todos . length > 0 || subagent || confirmation || question || subtaskRef
466+ const hasContent = textBefore || toolCalls . length > 0 || textAfter || thinkingContent || todos . length > 0 || subagent || confirmation || question
495467
496468 if ( ! hasContent && isCurrentMessage && isStreaming ) {
497469 return (
@@ -511,7 +483,6 @@ function AgentMessageContent({ message }: { message: Message }) {
511483 { textBefore && < MarkdownRenderer content = { textBefore } /> }
512484 { todos . length > 0 && < TodoSection todos = { todos } /> }
513485 { subagent && < SubagentSection subagent = { subagent } /> }
514- { subtaskRef && < SubtaskRefSection subtaskRef = { subtaskRef } /> }
515486 < ToolCallsList toolCalls = { toolCalls } />
516487 { confirmation && < ConfirmationSection confirmation = { confirmation } messageId = { message . id } /> }
517488 { question && < QuestionSection question = { question } /> }
0 commit comments