@@ -119,6 +119,15 @@ public static ModelContent FunctionResponse(
119119 /// single value of `Part`, different data types may not mix.
120120 /// </summary>
121121 public interface Part {
122+ /// <summary>
123+ /// Indicates whether this `Part` is a summary of the model's internal thinking process.
124+ ///
125+ /// When `IncludeThoughts` is set to `true` in `ThinkingConfig`, the model may return one or
126+ /// more "thought" parts that provide insight into how it reasoned through the prompt to arrive
127+ /// at the final answer. These parts will have `IsThought` set to `true`.
128+ /// </summary>
129+ public bool IsThought { get ; }
130+
122131#if ! DOXYGEN
123132 /// <summary>
124133 /// Intended for internal use only.
@@ -136,15 +145,39 @@ public interface Part {
136145 /// Text value.
137146 /// </summary>
138147 public string Text { get ; }
148+
149+ private readonly bool ? _isThought ;
150+ public bool IsThought { get { return _isThought ?? false ; } }
151+
152+ private readonly string _thoughtSignature ;
139153
140154 /// <summary>
141155 /// Creates a `TextPart` with the given text.
142156 /// </summary>
143157 /// <param name="text">The text value to use.</param>
144- public TextPart ( string text ) { Text = text ; }
158+ public TextPart ( string text ) {
159+ Text = text ;
160+ _isThought = null ;
161+ _thoughtSignature = null ;
162+ }
163+
164+ /// <summary>
165+ /// Intended for internal use only.
166+ /// </summary>
167+ internal TextPart ( string text , bool ? isThought , string thoughtSignature ) {
168+ Text = text ;
169+ _isThought = isThought ;
170+ _thoughtSignature = thoughtSignature ;
171+ }
145172
146173 Dictionary < string , object > Part . ToJson ( ) {
147- return new Dictionary < string , object > ( ) { { "text" , Text } } ;
174+ var jsonDict = new Dictionary < string , object > ( ) {
175+ { "text" , Text }
176+ } ;
177+
178+ jsonDict . AddIfHasValue ( "thought" , _isThought ) ;
179+ jsonDict . AddIfHasValue ( "thoughtSignature" , _thoughtSignature ) ;
180+ return jsonDict ;
148181 }
149182 }
150183
@@ -161,6 +194,11 @@ Dictionary<string, object> Part.ToJson() {
161194 /// The data provided in the inline data part.
162195 /// </summary>
163196 public byte [ ] Data { get ; }
197+
198+ private readonly bool ? _isThought ;
199+ public bool IsThought { get { return _isThought ?? false ; } }
200+
201+ private readonly string _thoughtSignature ;
164202
165203 /// <summary>
166204 /// Creates an `InlineDataPart` from data and a MIME type.
@@ -176,16 +214,31 @@ Dictionary<string, object> Part.ToJson() {
176214 /// <param name="data">The data representation of an image, video, audio or document; see [input files and
177215 /// requirements](https://firebase.google.com/docs/vertex-ai/input-file-requirements) for
178216 /// supported media types.</param>
179- public InlineDataPart ( string mimeType , byte [ ] data ) { MimeType = mimeType ; Data = data ; }
217+ public InlineDataPart ( string mimeType , byte [ ] data ) {
218+ MimeType = mimeType ;
219+ Data = data ;
220+ _isThought = null ;
221+ _thoughtSignature = null ;
222+ }
223+
224+ internal InlineDataPart ( string mimeType , byte [ ] data , bool ? isThought , string thoughtSignature ) {
225+ MimeType = mimeType ;
226+ Data = data ;
227+ _isThought = isThought ;
228+ _thoughtSignature = thoughtSignature ;
229+ }
180230
181231 Dictionary < string , object > Part . ToJson ( ) {
182- return new Dictionary < string , object > ( ) {
232+ var jsonDict = new Dictionary < string , object > ( ) {
183233 { "inlineData" , new Dictionary < string , object > ( ) {
184234 { "mimeType" , MimeType } ,
185235 { "data" , Convert . ToBase64String ( Data ) }
186236 }
187237 }
188238 } ;
239+ jsonDict . AddIfHasValue ( "thought" , _isThought ) ;
240+ jsonDict . AddIfHasValue ( "thoughtSignature" , _thoughtSignature ) ;
241+ return jsonDict ;
189242 }
190243 }
191244
@@ -201,6 +254,9 @@ Dictionary<string, object> Part.ToJson() {
201254 /// The URI of the file.
202255 /// </summary>
203256 public System . Uri Uri { get ; }
257+
258+ // This Part can only come from the user, and thus will never be a thought.
259+ public bool IsThought { get { return false ; } }
204260
205261 /// <summary>
206262 /// Constructs a new file data part.
@@ -241,27 +297,36 @@ Dictionary<string, object> Part.ToJson() {
241297 /// </summary>
242298 public string Id { get ; }
243299
300+ private readonly bool ? _isThought ;
301+ public bool IsThought { get { return _isThought ?? false ; } }
302+
303+ private readonly string _thoughtSignature ;
304+
244305 /// <summary>
245306 /// Intended for internal use only.
246307 /// </summary>
247- internal FunctionCallPart ( string name , IDictionary < string , object > args , string id ) {
308+ internal FunctionCallPart ( string name , IDictionary < string , object > args , string id ,
309+ bool ? isThought , string thoughtSignature ) {
248310 Name = name ;
249311 Args = new Dictionary < string , object > ( args ) ;
250312 Id = id ;
313+ _isThought = isThought ;
314+ _thoughtSignature = thoughtSignature ;
251315 }
252316
253317 Dictionary < string , object > Part . ToJson ( ) {
254- var jsonDict = new Dictionary < string , object > ( ) {
318+ var innerDict = new Dictionary < string , object > ( ) {
255319 { "name" , Name } ,
256320 { "args" , Args }
257321 } ;
258- if ( ! string . IsNullOrEmpty ( Id ) ) {
259- jsonDict [ "id" ] = Id ;
260- }
322+ innerDict . AddIfHasValue ( "id" , Id ) ;
261323
262- return new Dictionary < string , object > ( ) {
263- { "functionCall" , jsonDict }
324+ var jsonDict = new Dictionary < string , object > ( ) {
325+ { "functionCall" , innerDict }
264326 } ;
327+ jsonDict . AddIfHasValue ( "thought" , _isThought ) ;
328+ jsonDict . AddIfHasValue ( "thoughtSignature" , _thoughtSignature ) ;
329+ return jsonDict ;
265330 }
266331 }
267332
@@ -285,6 +350,9 @@ Dictionary<string, object> Part.ToJson() {
285350 /// The id from the FunctionCallPart this is in response to.
286351 /// </summary>
287352 public string Id { get ; }
353+
354+ // This Part can only come from the user, and thus will never be a thought.
355+ public bool IsThought { get { return false ; } }
288356
289357 /// <summary>
290358 /// Constructs a new `FunctionResponsePart`.
@@ -337,20 +405,27 @@ internal static ModelContent FromJson(Dictionary<string, object> jsonDict) {
337405 jsonDict . ParseObjectList ( "parts" , PartFromJson , JsonParseOptions . ThrowEverything ) . Where ( p => p is not null ) ) ;
338406 }
339407
340- private static InlineDataPart InlineDataPartFromJson ( Dictionary < string , object > jsonDict ) {
408+ private static InlineDataPart InlineDataPartFromJson ( Dictionary < string , object > jsonDict ,
409+ bool ? isThought , string thoughtSignature ) {
341410 return new InlineDataPart (
342411 jsonDict . ParseValue < string > ( "mimeType" , JsonParseOptions . ThrowEverything ) ,
343- Convert . FromBase64String ( jsonDict . ParseValue < string > ( "data" , JsonParseOptions . ThrowEverything ) ) ) ;
412+ Convert . FromBase64String ( jsonDict . ParseValue < string > ( "data" , JsonParseOptions . ThrowEverything ) ) ,
413+ isThought ,
414+ thoughtSignature ) ;
344415 }
345416
346417 private static Part PartFromJson ( Dictionary < string , object > jsonDict ) {
418+ bool ? isThought = jsonDict . ParseNullableValue < bool > ( "thought" ) ;
419+ string thoughtSignature = jsonDict . ParseValue < string > ( "thoughtSignature" ) ;
347420 if ( jsonDict . TryParseValue ( "text" , out string text ) ) {
348- return new TextPart ( text ) ;
349- } else if ( jsonDict . TryParseObject ( "functionCall" , ModelContentJsonParsers . FunctionCallPartFromJson ,
350- out var fcPart ) ) {
421+ return new TextPart ( text , isThought , thoughtSignature ) ;
422+ } else if ( jsonDict . TryParseObject ( "functionCall" ,
423+ innerDict => ModelContentJsonParsers . FunctionCallPartFromJson ( innerDict , isThought , thoughtSignature ) ,
424+ out var fcPart ) ) {
351425 return fcPart ;
352- } else if ( jsonDict . TryParseObject ( "inlineData" , InlineDataPartFromJson ,
353- out var inlineDataPart ) ) {
426+ } else if ( jsonDict . TryParseObject ( "inlineData" ,
427+ innerDict => InlineDataPartFromJson ( innerDict , isThought , thoughtSignature ) ,
428+ out var inlineDataPart ) ) {
354429 return inlineDataPart ;
355430 } else {
356431#if FIREBASEAI_DEBUG_LOGGING
@@ -365,11 +440,14 @@ namespace Internal {
365440
366441// Class for parsing Parts that need to be called from other files as well.
367442internal static class ModelContentJsonParsers {
368- internal static ModelContent . FunctionCallPart FunctionCallPartFromJson ( Dictionary < string , object > jsonDict ) {
443+ internal static ModelContent . FunctionCallPart FunctionCallPartFromJson ( Dictionary < string , object > jsonDict ,
444+ bool ? isThought , string thoughtSignature ) {
369445 return new ModelContent . FunctionCallPart (
370446 jsonDict . ParseValue < string > ( "name" , JsonParseOptions . ThrowEverything ) ,
371447 jsonDict . ParseValue < Dictionary < string , object > > ( "args" , JsonParseOptions . ThrowEverything ) ,
372- jsonDict . ParseValue < string > ( "id" ) ) ;
448+ jsonDict . ParseValue < string > ( "id" ) ,
449+ isThought ,
450+ thoughtSignature ) ;
373451 }
374452}
375453
0 commit comments