@@ -119,6 +119,15 @@ public static ModelContent FunctionResponse(
119
119
/// single value of `Part`, different data types may not mix.
120
120
/// </summary>
121
121
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
+
122
131
#if ! DOXYGEN
123
132
/// <summary>
124
133
/// Intended for internal use only.
@@ -136,15 +145,39 @@ public interface Part {
136
145
/// Text value.
137
146
/// </summary>
138
147
public string Text { get ; }
148
+
149
+ private readonly bool ? _isThought ;
150
+ public bool IsThought { get { return _isThought ?? false ; } }
151
+
152
+ private readonly string _thoughtSignature ;
139
153
140
154
/// <summary>
141
155
/// Creates a `TextPart` with the given text.
142
156
/// </summary>
143
157
/// <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
+ }
145
172
146
173
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 ;
148
181
}
149
182
}
150
183
@@ -161,6 +194,11 @@ Dictionary<string, object> Part.ToJson() {
161
194
/// The data provided in the inline data part.
162
195
/// </summary>
163
196
public byte [ ] Data { get ; }
197
+
198
+ private readonly bool ? _isThought ;
199
+ public bool IsThought { get { return _isThought ?? false ; } }
200
+
201
+ private readonly string _thoughtSignature ;
164
202
165
203
/// <summary>
166
204
/// Creates an `InlineDataPart` from data and a MIME type.
@@ -176,16 +214,31 @@ Dictionary<string, object> Part.ToJson() {
176
214
/// <param name="data">The data representation of an image, video, audio or document; see [input files and
177
215
/// requirements](https://firebase.google.com/docs/vertex-ai/input-file-requirements) for
178
216
/// 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
+ }
180
230
181
231
Dictionary < string , object > Part . ToJson ( ) {
182
- return new Dictionary < string , object > ( ) {
232
+ var jsonDict = new Dictionary < string , object > ( ) {
183
233
{ "inlineData" , new Dictionary < string , object > ( ) {
184
234
{ "mimeType" , MimeType } ,
185
235
{ "data" , Convert . ToBase64String ( Data ) }
186
236
}
187
237
}
188
238
} ;
239
+ jsonDict . AddIfHasValue ( "thought" , _isThought ) ;
240
+ jsonDict . AddIfHasValue ( "thoughtSignature" , _thoughtSignature ) ;
241
+ return jsonDict ;
189
242
}
190
243
}
191
244
@@ -201,6 +254,9 @@ Dictionary<string, object> Part.ToJson() {
201
254
/// The URI of the file.
202
255
/// </summary>
203
256
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 ; } }
204
260
205
261
/// <summary>
206
262
/// Constructs a new file data part.
@@ -241,27 +297,36 @@ Dictionary<string, object> Part.ToJson() {
241
297
/// </summary>
242
298
public string Id { get ; }
243
299
300
+ private readonly bool ? _isThought ;
301
+ public bool IsThought { get { return _isThought ?? false ; } }
302
+
303
+ private readonly string _thoughtSignature ;
304
+
244
305
/// <summary>
245
306
/// Intended for internal use only.
246
307
/// </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 ) {
248
310
Name = name ;
249
311
Args = new Dictionary < string , object > ( args ) ;
250
312
Id = id ;
313
+ _isThought = isThought ;
314
+ _thoughtSignature = thoughtSignature ;
251
315
}
252
316
253
317
Dictionary < string , object > Part . ToJson ( ) {
254
- var jsonDict = new Dictionary < string , object > ( ) {
318
+ var innerDict = new Dictionary < string , object > ( ) {
255
319
{ "name" , Name } ,
256
320
{ "args" , Args }
257
321
} ;
258
- if ( ! string . IsNullOrEmpty ( Id ) ) {
259
- jsonDict [ "id" ] = Id ;
260
- }
322
+ innerDict . AddIfHasValue ( "id" , Id ) ;
261
323
262
- return new Dictionary < string , object > ( ) {
263
- { "functionCall" , jsonDict }
324
+ var jsonDict = new Dictionary < string , object > ( ) {
325
+ { "functionCall" , innerDict }
264
326
} ;
327
+ jsonDict . AddIfHasValue ( "thought" , _isThought ) ;
328
+ jsonDict . AddIfHasValue ( "thoughtSignature" , _thoughtSignature ) ;
329
+ return jsonDict ;
265
330
}
266
331
}
267
332
@@ -285,6 +350,9 @@ Dictionary<string, object> Part.ToJson() {
285
350
/// The id from the FunctionCallPart this is in response to.
286
351
/// </summary>
287
352
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 ; } }
288
356
289
357
/// <summary>
290
358
/// Constructs a new `FunctionResponsePart`.
@@ -337,20 +405,27 @@ internal static ModelContent FromJson(Dictionary<string, object> jsonDict) {
337
405
jsonDict . ParseObjectList ( "parts" , PartFromJson , JsonParseOptions . ThrowEverything ) . Where ( p => p is not null ) ) ;
338
406
}
339
407
340
- private static InlineDataPart InlineDataPartFromJson ( Dictionary < string , object > jsonDict ) {
408
+ private static InlineDataPart InlineDataPartFromJson ( Dictionary < string , object > jsonDict ,
409
+ bool ? isThought , string thoughtSignature ) {
341
410
return new InlineDataPart (
342
411
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 ) ;
344
415
}
345
416
346
417
private static Part PartFromJson ( Dictionary < string , object > jsonDict ) {
418
+ bool ? isThought = jsonDict . ParseNullableValue < bool > ( "thought" ) ;
419
+ string thoughtSignature = jsonDict . ParseValue < string > ( "thoughtSignature" ) ;
347
420
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 ) ) {
351
425
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 ) ) {
354
429
return inlineDataPart ;
355
430
} else {
356
431
#if FIREBASEAI_DEBUG_LOGGING
@@ -365,11 +440,14 @@ namespace Internal {
365
440
366
441
// Class for parsing Parts that need to be called from other files as well.
367
442
internal 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 ) {
369
445
return new ModelContent . FunctionCallPart (
370
446
jsonDict . ParseValue < string > ( "name" , JsonParseOptions . ThrowEverything ) ,
371
447
jsonDict . ParseValue < Dictionary < string , object > > ( "args" , JsonParseOptions . ThrowEverything ) ,
372
- jsonDict . ParseValue < string > ( "id" ) ) ;
448
+ jsonDict . ParseValue < string > ( "id" ) ,
449
+ isThought ,
450
+ thoughtSignature ) ;
373
451
}
374
452
}
375
453
0 commit comments