@@ -66,70 +66,7 @@ fun AgentMessageList(
6666 verticalArrangement = Arrangement .spacedBy(6 .dp) // Reduce spacing
6767 ) {
6868 items(renderer.timeline) { timelineItem ->
69- when (timelineItem) {
70- is ComposeRenderer .TimelineItem .MessageItem -> {
71- MessageItem (
72- message = timelineItem.message,
73- tokenInfo = timelineItem.tokenInfo
74- )
75- }
76-
77- is ComposeRenderer .TimelineItem .CombinedToolItem -> {
78- CombinedToolItem (
79- toolName = timelineItem.toolName,
80- details = timelineItem.details,
81- fullParams = timelineItem.fullParams,
82- filePath = timelineItem.filePath,
83- toolType = timelineItem.toolType,
84- success = timelineItem.success,
85- summary = timelineItem.summary,
86- output = timelineItem.output,
87- fullOutput = timelineItem.fullOutput,
88- executionTimeMs = timelineItem.executionTimeMs,
89- docqlStats = timelineItem.docqlStats,
90- onOpenFileViewer = onOpenFileViewer
91- )
92- }
93-
94- is ComposeRenderer .TimelineItem .ToolResultItem -> {
95- ToolResultItem (
96- toolName = timelineItem.toolName,
97- success = timelineItem.success,
98- summary = timelineItem.summary,
99- output = timelineItem.output,
100- fullOutput = timelineItem.fullOutput
101- )
102- }
103-
104- is ComposeRenderer .TimelineItem .ToolErrorItem -> {
105- ToolErrorItem (error = timelineItem.error, onDismiss = { renderer.clearError() })
106- }
107-
108- is ComposeRenderer .TimelineItem .TaskCompleteItem -> {
109- TaskCompletedItem (
110- success = timelineItem.success,
111- message = timelineItem.message
112- )
113- }
114-
115- is ComposeRenderer .TimelineItem .TerminalOutputItem -> {
116- TerminalOutputItem (
117- command = timelineItem.command,
118- output = timelineItem.output,
119- exitCode = timelineItem.exitCode,
120- executionTimeMs = timelineItem.executionTimeMs
121- )
122- }
123-
124- is ComposeRenderer .TimelineItem .LiveTerminalItem -> {
125- LiveTerminalItem (
126- sessionId = timelineItem.sessionId,
127- command = timelineItem.command,
128- workingDirectory = timelineItem.workingDirectory,
129- ptyHandle = timelineItem.ptyHandle
130- )
131- }
132- }
69+ RenderMessageItem (timelineItem, onOpenFileViewer, renderer)
13370 }
13471
13572 if (renderer.currentStreamingOutput.isNotEmpty()) {
@@ -146,6 +83,78 @@ fun AgentMessageList(
14683 }
14784}
14885
86+ @Composable
87+ fun RenderMessageItem (
88+ timelineItem : ComposeRenderer .TimelineItem ,
89+ onOpenFileViewer : ((String ) -> Unit )? ,
90+ renderer : ComposeRenderer
91+ ) {
92+ when (timelineItem) {
93+ is ComposeRenderer .TimelineItem .MessageItem -> {
94+ MessageItem (
95+ message = timelineItem.message,
96+ tokenInfo = timelineItem.tokenInfo
97+ )
98+ }
99+
100+ is ComposeRenderer .TimelineItem .CombinedToolItem -> {
101+ CombinedToolItem (
102+ toolName = timelineItem.toolName,
103+ details = timelineItem.details,
104+ fullParams = timelineItem.fullParams,
105+ filePath = timelineItem.filePath,
106+ toolType = timelineItem.toolType,
107+ success = timelineItem.success,
108+ summary = timelineItem.summary,
109+ output = timelineItem.output,
110+ fullOutput = timelineItem.fullOutput,
111+ executionTimeMs = timelineItem.executionTimeMs,
112+ docqlStats = timelineItem.docqlStats,
113+ onOpenFileViewer = onOpenFileViewer
114+ )
115+ }
116+
117+ is ComposeRenderer .TimelineItem .ToolResultItem -> {
118+ ToolResultItem (
119+ toolName = timelineItem.toolName,
120+ success = timelineItem.success,
121+ summary = timelineItem.summary,
122+ output = timelineItem.output,
123+ fullOutput = timelineItem.fullOutput
124+ )
125+ }
126+
127+ is ComposeRenderer .TimelineItem .ToolErrorItem -> {
128+ ToolErrorItem (error = timelineItem.error, onDismiss = { renderer.clearError() })
129+ }
130+
131+ is ComposeRenderer .TimelineItem .TaskCompleteItem -> {
132+ TaskCompletedItem (
133+ success = timelineItem.success,
134+ message = timelineItem.message
135+ )
136+ }
137+
138+ is ComposeRenderer .TimelineItem .TerminalOutputItem -> {
139+ TerminalOutputItem (
140+ command = timelineItem.command,
141+ output = timelineItem.output,
142+ exitCode = timelineItem.exitCode,
143+ executionTimeMs = timelineItem.executionTimeMs
144+ )
145+ }
146+
147+ is ComposeRenderer .TimelineItem .LiveTerminalItem -> {
148+ LiveTerminalItem (
149+ sessionId = timelineItem.sessionId,
150+ command = timelineItem.command,
151+ workingDirectory = timelineItem.workingDirectory,
152+ ptyHandle = timelineItem.ptyHandle
153+ )
154+ }
155+ }
156+ }
157+
149158/* *
150159 * Platform-specific live terminal display.
151160 * On JVM with PTY support: Renders an interactive terminal widget
@@ -177,23 +186,20 @@ fun MessageItem(
177186 ) {
178187 PlatformMessageTextContainer (text = message.content) {
179188 Column (modifier = Modifier .padding(8 .dp)) {
180- // Use SketchRenderer for assistant messages to support thinking blocks
181189 if (! isUser) {
182190 SketchRenderer .RenderResponse (
183191 content = message.content,
184192 isComplete = true ,
185193 modifier = Modifier .fillMaxWidth()
186194 )
187195 } else {
188- // For user messages, use simple text
189196 Text (
190197 text = message.content,
191198 fontFamily = if (Platform .isWasm) FontFamily (Font (Res .font.NotoSansSC_Regular )) else FontFamily .Monospace ,
192199 style = MaterialTheme .typography.bodyMedium
193200 )
194201 }
195202
196- // Display token info if available (only for assistant messages)
197203 if (! isUser && tokenInfo != null && tokenInfo.totalTokens > 0 ) {
198204 Spacer (modifier = Modifier .height(4 .dp))
199205 Text (
0 commit comments