@@ -180,53 +180,60 @@ static async Task<ChatResponse> ToChatResponseAsync(
180180        } 
181181    } 
182182
183-     /// <summary>Coalesces sequential <see cref="TextContent "/> content elements.</summary> 
183+     /// <summary>Coalesces sequential <see cref="AIContent "/> content elements.</summary> 
184184    internal  static   void  CoalesceTextContent ( List < AIContent >  contents ) 
185185    { 
186-         StringBuilder ?  coalescedText  =  null ; 
186+         Coalesce < TextContent > ( contents ,  static  text =>  new ( text ) ) ; 
187+         Coalesce < TextReasoningContent > ( contents ,  static  text =>  new ( text ) ) ; 
187188
188-         // Iterate through all of the items in the list looking for contiguous items that can be coalesced . 
189-         int   start   =   0 ; 
190-         while   ( start   <   contents . Count   -   1 ) 
189+         // This implementation relies on TContent's ToString returning its exact text . 
190+         static   void   Coalesce < TContent > ( List < AIContent >   contents ,   Func < string ,   TContent >   fromText ) 
191+              where   TContent   :   AIContent 
191192        { 
192-             // We need at least two TextContents in a row to be able to coalesce. 
193-             if  ( contents [ start ]  is  not TextContent  firstText ) 
194-             { 
195-                 start ++ ; 
196-                 continue ; 
197-             } 
198- 
199-             if  ( contents [ start  +  1 ]  is  not TextContent  secondText ) 
200-             { 
201-                 start  +=  2 ; 
202-                 continue ; 
203-             } 
193+             StringBuilder ?  coalescedText  =  null ; 
204194
205-             // Append the text from those nodes and continue appending subsequent TextContents until we run out. 
206-             // We null out nodes as their text is appended so that we can later remove them all in one O(N) operation. 
207-             coalescedText  ??=  new ( ) ; 
208-             _  =  coalescedText . Clear ( ) . Append ( firstText . Text ) . Append ( secondText . Text ) ; 
209-             contents [ start  +  1 ]  =  null ! ; 
210-             int  i  =  start  +  2 ; 
211-             for  ( ;  i  <  contents . Count  &&  contents [ i ]  is  TextContent  next ;  i ++ ) 
195+             // Iterate through all of the items in the list looking for contiguous items that can be coalesced. 
196+             int  start  =  0 ; 
197+             while  ( start  <  contents . Count  -  1 ) 
212198            { 
213-                 _  =  coalescedText . Append ( next . Text ) ; 
214-                 contents [ i ]  =  null ! ; 
199+                 // We need at least two TextContents in a row to be able to coalesce. 
200+                 if  ( contents [ start ]  is  not TContent  firstText ) 
201+                 { 
202+                     start ++ ; 
203+                     continue ; 
204+                 } 
205+ 
206+                 if  ( contents [ start  +  1 ]  is  not TContent  secondText ) 
207+                 { 
208+                     start  +=  2 ; 
209+                     continue ; 
210+                 } 
211+ 
212+                 // Append the text from those nodes and continue appending subsequent TextContents until we run out. 
213+                 // We null out nodes as their text is appended so that we can later remove them all in one O(N) operation. 
214+                 coalescedText  ??=  new ( ) ; 
215+                 _  =  coalescedText . Clear ( ) . Append ( firstText ) . Append ( secondText ) ; 
216+                 contents [ start  +  1 ]  =  null ! ; 
217+                 int  i  =  start  +  2 ; 
218+                 for  ( ;  i  <  contents . Count  &&  contents [ i ]  is  TContent  next ;  i ++ ) 
219+                 { 
220+                     _  =  coalescedText . Append ( next ) ; 
221+                     contents [ i ]  =  null ! ; 
222+                 } 
223+ 
224+                 // Store the replacement node. We inherit the properties of the first text node. We don't 
225+                 // currently propagate additional properties from the subsequent nodes. If we ever need to, 
226+                 // we can add that here. 
227+                 var  newContent  =  fromText ( coalescedText . ToString ( ) ) ; 
228+                 contents [ start ]  =  newContent ; 
229+                 newContent . AdditionalProperties  =  firstText . AdditionalProperties ? . Clone ( ) ; 
230+ 
231+                 start  =  i ; 
215232            } 
216233
217-             // Store the replacement node. 
218-             contents [ start ]  =  new  TextContent ( coalescedText . ToString ( ) ) 
219-             { 
220-                 // We inherit the properties of the first text node. We don't currently propagate additional 
221-                 // properties from the subsequent nodes. If we ever need to, we can add that here. 
222-                 AdditionalProperties  =  firstText . AdditionalProperties ? . Clone ( ) , 
223-             } ; 
224- 
225-             start  =  i ; 
234+             // Remove all of the null slots left over from the coalescing process. 
235+             _  =  contents . RemoveAll ( u =>  u  is  null ) ; 
226236        } 
227- 
228-         // Remove all of the null slots left over from the coalescing process. 
229-         _  =  contents . RemoveAll ( u =>  u  is  null ) ; 
230237    } 
231238
232239    /// <summary>Finalizes the <paramref name="response"/> object.</summary> 
0 commit comments