@@ -19,35 +19,21 @@ import Foundation
1919@available ( iOS 15 . 0 ,  macOS 12 . 0 ,  macCatalyst 15 . 0 ,  tvOS 15 . 0 ,  watchOS 8 . 0 ,  * )  
2020public  final  class  Chat :  Sendable  { 
2121  private  let  model :  GenerativeModel 
22+   private  let  _history :  History 
2223
23-   /// Initializes a new chat representing a 1:1 conversation between model and user.
2424  init ( model:  GenerativeModel ,  history:  [ ModelContent ] )  { 
2525    self . model =  model
26-     self . history  =  history
26+     _history  =  History ( history:  history ) 
2727  } 
2828
29-   private  let  historyLock   =  NSLock ( ) 
30-   private  nonisolated ( unsafe)  var  _history :  [ ModelContent ]  =  [ ] 
3129  /// The previous content from the chat that has been successfully sent and received from the
3230  /// model. This will be provided to the model for each message sent as context for the discussion.
3331  public  var  history :  [ ModelContent ]  { 
3432    get  { 
35-       historyLock . withLock   {   _history  } 
33+       return   _history. history 
3634    } 
3735    set  { 
38-       historyLock. withLock  {  _history =  newValue } 
39-     } 
40-   } 
41- 
42-   private  func  appendHistory( contentsOf:  [ ModelContent ] )  { 
43-     historyLock. withLock  { 
44-       _history. append ( contentsOf:  contentsOf) 
45-     } 
46-   } 
47- 
48-   private  func  appendHistory( _ newElement:  ModelContent )  { 
49-     historyLock. withLock  { 
50-       _history. append ( newElement) 
36+       _history. history =  newValue
5137    } 
5238  } 
5339
@@ -87,8 +73,8 @@ public final class Chat: Sendable {
8773    let  toAdd  =  ModelContent ( role:  " model " ,  parts:  reply. parts) 
8874
8975    // Append the request and successful result to history, then return the value.
90-     appendHistory ( contentsOf:  newContent) 
91-     appendHistory ( toAdd) 
76+     _history . append ( contentsOf:  newContent) 
77+     _history . append ( toAdd) 
9278    return  result
9379  } 
9480
@@ -136,63 +122,16 @@ public final class Chat: Sendable {
136122        } 
137123
138124        // Save the request.
139-         appendHistory ( contentsOf:  newContent) 
125+         _history . append ( contentsOf:  newContent) 
140126
141127        // Aggregate the content to add it to the history before we finish.
142-         let  aggregated  =  self . aggregatedChunks ( aggregatedContent) 
143-         self . appendHistory ( aggregated) 
128+         let  aggregated  =  self . _history . aggregatedChunks ( aggregatedContent) 
129+         self . _history . append ( aggregated) 
144130        continuation. finish ( ) 
145131      } 
146132    } 
147133  } 
148134
149-   private  func  aggregatedChunks( _ chunks:  [ ModelContent ] )  ->  ModelContent  { 
150-     var  parts :  [ InternalPart ]  =  [ ] 
151-     var  combinedText  =  " " 
152-     var  combinedThoughts  =  " " 
153- 
154-     func  flush( )  { 
155-       if  !combinedThoughts. isEmpty { 
156-         parts. append ( InternalPart ( . text( combinedThoughts) ,  isThought:  true ,  thoughtSignature:  nil ) ) 
157-         combinedThoughts =  " " 
158-       } 
159-       if  !combinedText. isEmpty { 
160-         parts. append ( InternalPart ( . text( combinedText) ,  isThought:  nil ,  thoughtSignature:  nil ) ) 
161-         combinedText =  " " 
162-       } 
163-     } 
164- 
165-     // Loop through all the parts, aggregating the text.
166-     for  part  in  chunks. flatMap ( {  $0. internalParts } )  { 
167-       // Only text parts may be combined.
168-       if  case let  . text( text)  =  part. data,  part. thoughtSignature ==  nil  { 
169-         // Thought summaries must not be combined with regular text.
170-         if  part. isThought ??  false  { 
171-           // If we were combining regular text, flush it before handling "thoughts".
172-           if  !combinedText. isEmpty { 
173-             flush ( ) 
174-           } 
175-           combinedThoughts +=  text
176-         }  else  { 
177-           // If we were combining "thoughts", flush it before handling regular text.
178-           if  !combinedThoughts. isEmpty { 
179-             flush ( ) 
180-           } 
181-           combinedText +=  text
182-         } 
183-       }  else  { 
184-         // This is a non-combinable part (not text), flush any pending text.
185-         flush ( ) 
186-         parts. append ( part) 
187-       } 
188-     } 
189- 
190-     // Flush any remaining text.
191-     flush ( ) 
192- 
193-     return  ModelContent ( role:  " model " ,  parts:  parts) 
194-   } 
195- 
196135  /// Populates the `role` field with `user` if it doesn't exist. Required in chat sessions.
197136  private  func  populateContentRole( _ content:  ModelContent )  ->  ModelContent  { 
198137    if  content. role !=  nil  { 
0 commit comments