@@ -968,7 +968,10 @@ function SessionRowView(props: { row: SessionRow; message: (messageID: string) =
968968 < Match when = { props . row . type === "part" ? props . row : undefined } >
969969 { ( row ) => < SessionPartView partRef = { row ( ) . ref } message = { props . message } /> }
970970 </ Match >
971- < Match when = { props . row . type === "group" ? props . row : undefined } >
971+ < Match when = { props . row . type === "group" && props . row . kind === "reasoning" ? props . row : undefined } >
972+ { ( row ) => < SessionReasoningGroupView refs = { row ( ) . refs } completed = { row ( ) . completed } message = { props . message } /> }
973+ </ Match >
974+ < Match when = { props . row . type === "group" && props . row . kind === "exploration" ? props . row : undefined } >
972975 { ( row ) => (
973976 < SessionGroupView
974977 refs = { row ( ) . refs }
@@ -1078,6 +1081,114 @@ function SessionPartView(props: { partRef: PartRef; message: (messageID: string)
10781081 )
10791082}
10801083
1084+ function SessionReasoningGroupView ( props : {
1085+ refs : PartRef [ ]
1086+ completed : boolean
1087+ message : ( messageID : string ) => SessionMessageInfo | undefined
1088+ } ) {
1089+ const ctx = use ( )
1090+ const { theme, syntax } = useTheme ( )
1091+ const renderer = useRenderer ( )
1092+ const [ expanded , setExpanded ] = createSignal ( false )
1093+ const parts = createMemo < { message : SessionMessageAssistant ; part : SessionMessageAssistantReasoning } [ ] > (
1094+ ( previous ) => {
1095+ const next = props . refs . flatMap ( ( ref ) => {
1096+ const message = props . message ( ref . messageID )
1097+ if ( message ?. type !== "assistant" ) return [ ]
1098+ const part = resolvePart ( message , ref . partID )
1099+ if ( part ?. type !== "reasoning" || ! part . text . replace ( "[REDACTED]" , "" ) . trim ( ) ) return [ ]
1100+ return [ { message, part } ]
1101+ } )
1102+ return next . length > 0 ? next : previous
1103+ } ,
1104+ [ ] as { message : SessionMessageAssistant ; part : SessionMessageAssistantReasoning } [ ] ,
1105+ )
1106+ const latest = createMemo ( ( previous : string | null ) => {
1107+ const item = parts ( ) . at ( - 1 )
1108+ if ( ! item ) return previous
1109+ const title = reasoningSummary ( item . part . text . replace ( "[REDACTED]" , "" ) . trim ( ) ) . title
1110+ if ( title ) return title
1111+ if ( item . part . time ?. completed !== undefined || item . message . time . completed !== undefined ) return null
1112+ return previous
1113+ } , null )
1114+ const duration = createMemo ( ( ) =>
1115+ parts ( ) . reduce ( ( total , item ) => {
1116+ const end = item . part . time ?. completed ?? item . message . time . completed
1117+ const start = item . part . time ?. created ?? item . message . time . created
1118+ return total + ( end === undefined ? 0 : Math . max ( 0 , end - start ) )
1119+ } , 0 ) ,
1120+ )
1121+
1122+ return (
1123+ < Show when = { parts ( ) . length > 0 } >
1124+ < Show
1125+ when = { ctx . thinkingMode ( ) === "hide" }
1126+ fallback = {
1127+ < For each = { parts ( ) } > { ( item ) => < ReasoningPart part = { item . part } message = { item . message } last = { false } /> } </ For >
1128+ }
1129+ >
1130+ < box paddingLeft = { 3 } flexDirection = "column" flexShrink = { 0 } >
1131+ < box
1132+ onMouseUp = { ( ) => {
1133+ if ( renderer . getSelection ( ) ?. getSelectedText ( ) ) return
1134+ setExpanded ( ( value ) => ! value )
1135+ } }
1136+ >
1137+ < Show
1138+ when = { props . completed }
1139+ fallback = { < Spinner color = { theme . warning } > { latest ( ) ? `Thinking: ${ latest ( ) } ` : "Thinking" } </ Spinner > }
1140+ >
1141+ < Show
1142+ when = { expanded ( ) }
1143+ fallback = {
1144+ < text fg = { theme . warning } wrapMode = "none" >
1145+ + Thought
1146+ < Show when = { latest ( ) } > : { latest ( ) } </ Show >
1147+ < Show when = { parts ( ) . length > 1 } > · { parts ( ) . length } steps</ Show >
1148+ < Show when = { duration ( ) } > · { Locale . duration ( duration ( ) ) } </ Show >
1149+ </ text >
1150+ }
1151+ >
1152+ < text fg = { theme . warning } wrapMode = "none" >
1153+ - Thought
1154+ < Show when = { parts ( ) . length > 1 } > · { parts ( ) . length } steps</ Show >
1155+ < Show when = { duration ( ) } > · { Locale . duration ( duration ( ) ) } </ Show >
1156+ </ text >
1157+ </ Show >
1158+ </ Show >
1159+ </ box >
1160+ < Show when = { expanded ( ) } >
1161+ < For each = { parts ( ) } >
1162+ { ( item ) => {
1163+ const content = createMemo ( ( ) => item . part . text . replace ( "[REDACTED]" , "" ) . trim ( ) )
1164+ const summary = createMemo ( ( ) => reasoningSummary ( content ( ) ) )
1165+ const markdown = createMemo ( ( ) => {
1166+ if ( ! summary ( ) . title ) return content ( )
1167+ if ( ! summary ( ) . body ) return `**${ summary ( ) . title } **`
1168+ return `**${ summary ( ) . title } ** · ${ summary ( ) . body } `
1169+ } )
1170+ return (
1171+ < box marginTop = { 1 } >
1172+ < code
1173+ filetype = "markdown"
1174+ drawUnstyledText = { false }
1175+ streaming = { false }
1176+ syntaxStyle = { syntax ( ) }
1177+ content = { markdown ( ) }
1178+ conceal = { ctx . markdownMode ( ) === "rendered" }
1179+ fg = { theme . textMuted }
1180+ />
1181+ </ box >
1182+ )
1183+ } }
1184+ </ For >
1185+ </ Show >
1186+ </ box >
1187+ </ Show >
1188+ </ Show >
1189+ )
1190+ }
1191+
10811192function SessionGroupView ( props : {
10821193 refs : PartRef [ ]
10831194 pending : PartRef [ ]
0 commit comments