@@ -8,7 +8,8 @@ mock.module("@deepagent-code/ui/message-part", () => ({
88 type : "part" ,
99 ref : { messageID : item . messageID , partID : item . part . id } ,
1010 } ) ) ,
11- renderable : ( ) => true ,
11+ renderable : ( part : Part , showReasoningSummaries = true ) =>
12+ part . type !== "reasoning" || showReasoningSummaries ,
1213} ) )
1314
1415afterAll ( ( ) => mock . restore ( ) )
@@ -122,7 +123,7 @@ describe("message timeline activity progress", () => {
122123 } ,
123124 } ) as Part
124125
125- test ( "shows only the latest settled progress for one activity" , async ( ) => {
126+ test ( "renders every progress revision for one activity" , async ( ) => {
126127 const { Timeline } = await import ( "./message-timeline.data" )
127128 const messages = [ assistant ( "msg_a0" ) , assistant ( "msg_a1" ) ]
128129 const parts = new Map ( [
@@ -133,10 +134,10 @@ describe("message timeline activity progress", () => {
133134 const rows = Timeline . constructMessageRows ( user , ( id ) => parts . get ( id ) ?? [ ] , messages , 0 , false , "idle" , false )
134135 expect (
135136 rows . flatMap ( ( row ) => ( row . _tag === "AssistantPart" && row . group . type === "part" ? [ row . group . ref . partID ] : [ ] ) ) ,
136- ) . toEqual ( [ "prt_progress_1" ] )
137+ ) . toEqual ( [ "prt_progress_0" , " prt_progress_1"] )
137138 } )
138139
139- test ( "replaces settled progress with the activity final" , async ( ) => {
140+ test ( "keeps progress revisions when the activity final arrives " , async ( ) => {
140141 const { Timeline } = await import ( "./message-timeline.data" )
141142 const messages = [ assistant ( "msg_a0" ) , assistant ( "msg_a1" ) , { ...assistant ( "msg_a2" ) , finish : "stop" } ]
142143 const parts = new Map ( [
@@ -148,10 +149,10 @@ describe("message timeline activity progress", () => {
148149 const rows = Timeline . constructMessageRows ( user , ( id ) => parts . get ( id ) ?? [ ] , messages , 0 , false , "idle" , false )
149150 expect (
150151 rows . flatMap ( ( row ) => ( row . _tag === "AssistantPart" && row . group . type === "part" ? [ row . group . ref . partID ] : [ ] ) ) ,
151- ) . toEqual ( [ "prt_final_2" ] )
152+ ) . toEqual ( [ "prt_progress_0" , "prt_progress_1" , " prt_final_2"] )
152153 } )
153154
154- test ( "collapses every text part in one activity across separate parent user rows" , async ( ) => {
155+ test ( "keeps text parts across separate parent user rows" , async ( ) => {
155156 const { Timeline } = await import ( "./message-timeline.data" )
156157 const user2 = { ...user , id : "msg_user_2" }
157158 const firstAssistant = assistant ( "msg_cross_a0" )
@@ -173,7 +174,6 @@ describe("message timeline activity progress", () => {
173174 ] ,
174175 ] )
175176 const getParts = ( id : string ) => parts . get ( id ) ?? [ ]
176- const visibility = Timeline . activityProgressVisibility ( messages , getParts )
177177 const firstRows = Timeline . constructMessageRows (
178178 user ,
179179 getParts ,
@@ -182,7 +182,6 @@ describe("message timeline activity progress", () => {
182182 false ,
183183 "idle" ,
184184 false ,
185- visibility ,
186185 )
187186 const secondRows = Timeline . constructMessageRows (
188187 user2 ,
@@ -192,17 +191,20 @@ describe("message timeline activity progress", () => {
192191 false ,
193192 "idle" ,
194193 false ,
195- visibility ,
196194 )
197- expect ( firstRows . some ( ( row ) => row . _tag === "AssistantPart" ) ) . toBe ( false )
195+ expect (
196+ firstRows . flatMap ( ( row ) =>
197+ row . _tag === "AssistantPart" && row . group . type === "part" ? [ row . group . ref . partID ] : [ ] ,
198+ ) ,
199+ ) . toEqual ( [ "prt_progress_0" , "prt_cross_old_plain" ] )
198200 expect (
199201 secondRows . flatMap ( ( row ) =>
200202 row . _tag === "AssistantPart" && row . group . type === "part" ? [ row . group . ref . partID ] : [ ] ,
201203 ) ,
202204 ) . toEqual ( [ "prt_progress_1" , "prt_cross_latest_plain" ] )
203205 } )
204206
205- test ( "applies one revision marker to every text part in the assistant message " , async ( ) => {
207+ test ( "keeps every text part in every revision " , async ( ) => {
206208 const { Timeline } = await import ( "./message-timeline.data" )
207209 const messages = [ assistant ( "msg_multi_a0" ) , { ...assistant ( "msg_multi_a1" ) , finish : "stop" } ]
208210 const plain = ( messageID : string , id : string , text : string ) =>
@@ -219,10 +221,10 @@ describe("message timeline activity progress", () => {
219221
220222 expect (
221223 rows . flatMap ( ( row ) => ( row . _tag === "AssistantPart" && row . group . type === "part" ? [ row . group . ref . partID ] : [ ] ) ) ,
222- ) . toEqual ( [ "prt_final_1" , "prt_final_plain" ] )
224+ ) . toEqual ( [ "prt_progress_0" , "prt_old_plain" , " prt_final_1", "prt_final_plain" ] )
223225 } )
224226
225- test ( "uses the message marker to collapse reasoning-only revisions " , async ( ) => {
227+ test ( "keeps reasoning summaries from every revision when enabled " , async ( ) => {
226228 const { Timeline } = await import ( "./message-timeline.data" )
227229 const messages = [
228230 {
@@ -245,19 +247,34 @@ describe("message timeline activity progress", () => {
245247
246248 expect (
247249 rows . flatMap ( ( row ) => ( row . _tag === "AssistantPart" && row . group . type === "part" ? [ row . group . ref . partID ] : [ ] ) ) ,
248- ) . toEqual ( [ "prt_reasoning_latest" ] )
250+ ) . toEqual ( [ "prt_reasoning_old" , " prt_reasoning_latest"] )
249251 } )
250252
251- test ( "hides an older tool revision when the latest terminal message has no renderable parts" , async ( ) => {
253+ test ( "uses showReasoning as the explicit reasoning visibility control" , async ( ) => {
254+ const { Timeline } = await import ( "./message-timeline.data" )
255+ const message = assistant ( "msg_reasoning_setting" )
256+ const reasoning = {
257+ id : "prt_reasoning_setting" ,
258+ sessionID : user . sessionID ,
259+ messageID : message . id ,
260+ type : "reasoning" ,
261+ text : "summary" ,
262+ } as Part
263+ const getParts = ( ) => [ reasoning ]
264+
265+ const hidden = Timeline . constructMessageRows ( user , getParts , [ message ] , 0 , false , "idle" , false )
266+ const shown = Timeline . constructMessageRows ( user , getParts , [ message ] , 0 , true , "idle" , false )
267+
268+ expect ( hidden . some ( ( row ) => row . _tag === "AssistantPart" ) ) . toBe ( false )
269+ expect ( shown . some ( ( row ) => row . _tag === "AssistantPart" ) ) . toBe ( true )
270+ } )
271+
272+ test ( "keeps an older tool revision when a later terminal message has no renderable parts" , async ( ) => {
252273 const { Timeline } = await import ( "./message-timeline.data" )
253274 const old = {
254275 ...assistant ( "msg_tool_old" ) ,
255276 activityProgress : { activityID : "activity-tool" , revision : 0 , state : "progress" as const } ,
256277 }
257- const terminal = {
258- ...assistant ( "msg_tool_terminal" ) ,
259- activityProgress : { activityID : "activity-tool" , revision : 1 , state : "final" as const } ,
260- }
261278 const tool = {
262279 id : "prt_tool_old" ,
263280 sessionID : user . sessionID ,
@@ -268,10 +285,8 @@ describe("message timeline activity progress", () => {
268285 state : { status : "completed" , input : { } , output : "pending" , title : "poll" , time : { start : 1 , end : 2 } } ,
269286 } as Part
270287 const parts = new Map ( [ [ old . id , [ tool ] ] ] )
271- const visibility = Timeline . activityProgressVisibility ( [ old , terminal ] , ( id ) => parts . get ( id ) ?? [ ] )
272-
273- const rows = Timeline . constructMessageRows ( user , ( id ) => parts . get ( id ) ?? [ ] , [ old ] , 0 , true , "idle" , false , visibility )
288+ const rows = Timeline . constructMessageRows ( user , ( id ) => parts . get ( id ) ?? [ ] , [ old ] , 0 , true , "idle" , false )
274289
275- expect ( rows . some ( ( row ) => row . _tag === "AssistantPart" ) ) . toBe ( false )
290+ expect ( rows . some ( ( row ) => row . _tag === "AssistantPart" ) ) . toBe ( true )
276291 } )
277292} )
0 commit comments