1414
1515import 'content.dart' ;
1616import 'error.dart' ;
17- import 'function_calling.dart' show Tool, ToolConfig;
1817import 'schema.dart' ;
18+ import 'tool.dart' show Tool, ToolConfig;
1919
2020/// Response for Count Tokens
2121final class CountTokensResponse {
@@ -196,7 +196,8 @@ final class Candidate {
196196 // TODO: token count?
197197 // ignore: public_member_api_docs
198198 Candidate (this .content, this .safetyRatings, this .citationMetadata,
199- this .finishReason, this .finishMessage);
199+ this .finishReason, this .finishMessage,
200+ {this .groundingMetadata});
200201
201202 /// Generated content returned from the model.
202203 final Content content;
@@ -221,6 +222,9 @@ final class Candidate {
221222 /// Message for finish reason.
222223 final String ? finishMessage;
223224
225+ /// Metadata returned to the client when grounding is enabled.
226+ final GroundingMetadata ? groundingMetadata;
227+
224228 /// The concatenation of the text parts of [content] , if any.
225229 ///
226230 /// If this candidate was finished for a reason of [FinishReason.recitation]
@@ -252,6 +256,150 @@ final class Candidate {
252256 }
253257}
254258
259+ /// Represents a specific segment within a [Content] , often used to pinpoint
260+ /// the exact location of text or data that grounding information refers to.
261+ final class Segment {
262+ // ignore: public_member_api_docs
263+ Segment (
264+ {required this .partIndex,
265+ required this .startIndex,
266+ required this .endIndex,
267+ required this .text});
268+
269+ /// The zero-based index of the [Part] object within the `parts` array of its
270+ /// parent [Content] object.
271+ ///
272+ /// This identifies which part of the content the segment belongs to.
273+ final int partIndex;
274+
275+ /// The zero-based start index of the segment within the specified [Part] ,
276+ /// measured in UTF-8 bytes.
277+ ///
278+ /// This offset is inclusive, starting from 0 at the beginning of the
279+ /// part's content.
280+ final int startIndex;
281+
282+ /// The zero-based end index of the segment within the specified [Part] ,
283+ /// measured in UTF-8 bytes.
284+ ///
285+ /// This offset is exclusive, meaning the character at this index is not
286+ /// included in the segment.
287+ final int endIndex;
288+
289+ /// The text corresponding to the segment from the response.
290+ final String text;
291+ }
292+
293+ /// A grounding chunk sourced from the web.
294+ final class WebGroundingChunk {
295+ // ignore: public_member_api_docs
296+ WebGroundingChunk ({this .uri, this .title, this .domain});
297+
298+ /// The URI of the retrieved web page.
299+ final String ? uri;
300+
301+ /// The title of the retrieved web page.
302+ final String ? title;
303+
304+ /// The domain of the original URI from which the content was retrieved.
305+ ///
306+ /// This field is only populated when using the Vertex AI Gemini API.
307+ final String ? domain;
308+ }
309+
310+ /// Represents a chunk of retrieved data that supports a claim in the model's
311+ /// response.
312+ ///
313+ /// This is part of the grounding information provided when grounding is
314+ /// enabled.
315+ final class GroundingChunk {
316+ // ignore: public_member_api_docs
317+ GroundingChunk ({this .web});
318+
319+ /// Contains details if the grounding chunk is from a web source.
320+ final WebGroundingChunk ? web;
321+ }
322+
323+ /// Provides information about how a specific segment of the model's response
324+ /// is supported by the retrieved grounding chunks.
325+ final class GroundingSupport {
326+ // ignore: public_member_api_docs
327+ GroundingSupport (
328+ {required this .segment, required this .groundingChunkIndices});
329+
330+ /// Specifies the segment of the model's response content that this
331+ /// grounding support pertains to.
332+ final Segment segment;
333+
334+ /// A list of indices that refer to specific [GroundingChunk] s within the
335+ /// [GroundingMetadata.groundingChunks] array.
336+ ///
337+ /// These referenced chunks are the sources that
338+ /// support the claim made in the associated `segment` of the response.
339+ /// For example, an array `[1, 3, 4]`
340+ /// means that `groundingChunks[1]` , `groundingChunks[3]` , and
341+ /// `groundingChunks[4]` are the
342+ /// retrieved content supporting this part of the response.
343+ final List <int > groundingChunkIndices;
344+ }
345+
346+ /// Google Search entry point for web searches.
347+ final class SearchEntryPoint {
348+ // ignore: public_member_api_docs
349+ SearchEntryPoint ({required this .renderedContent});
350+
351+ /// An HTML/CSS snippet that **must** be embedded in an app to display a
352+ /// Google Search entry point for follow-up web searches related to the
353+ /// model's "Grounded Response".
354+ ///
355+ /// To ensure proper rendering, it's recommended to display this content
356+ /// within a `WebView` .
357+ final String renderedContent;
358+ }
359+
360+ /// Metadata returned to the client when grounding is enabled.
361+ ///
362+ /// > Important: If using Grounding with Google Search, you are required to
363+ /// comply with the "Grounding with Google Search" usage requirements for your
364+ /// chosen API provider:
365+ /// [Gemini Developer API] (https://ai.google.dev/gemini-api/terms#grounding-with-google-search)
366+ /// or Vertex AI Gemini API (see [Service Terms] (https://cloud.google.com/terms/service-terms)
367+ /// section within the Service Specific Terms).
368+ final class GroundingMetadata {
369+ // ignore: public_member_api_docs
370+ GroundingMetadata (
371+ {this .searchEntryPoint,
372+ required this .groundingChunks,
373+ required this .groundingSupport,
374+ required this .webSearchQueries});
375+
376+ /// Google Search entry point for web searches.
377+ ///
378+ /// This contains an HTML/CSS snippet that **must** be embedded in an app to
379+ // display a Google Search entry point for follow-up web searches related to
380+ // the model's "Grounded Response".
381+ final SearchEntryPoint ? searchEntryPoint;
382+
383+ /// A list of [GroundingChunk] s.
384+ ///
385+ /// Each chunk represents a piece of retrieved content (e.g., from a web
386+ /// page) that the model used to ground its response.
387+ final List <GroundingChunk > groundingChunks;
388+
389+ /// A list of [GroundingSupport] s.
390+ ///
391+ /// Each object details how specific segments of the
392+ /// model's response are supported by the `groundingChunks` .
393+ final List <GroundingSupport > groundingSupport;
394+
395+ /// A list of web search queries that the model performed to gather the
396+ /// grounding information.
397+ ///
398+ /// These can be used to allow users to explore the search results
399+ /// themselves.
400+ final List <String > webSearchQueries;
401+ }
402+
255403/// Safety rating for a piece of content.
256404///
257405/// The safety rating contains the category of harm and the harm probability
@@ -1060,29 +1208,33 @@ Candidate _parseCandidate(Object? jsonObject) {
10601208 }
10611209
10621210 return Candidate (
1063- jsonObject.containsKey ('content' )
1064- ? parseContent (jsonObject['content' ] as Object )
1065- : Content (null , []),
1066- switch (jsonObject) {
1067- {'safetyRatings' : final List <Object ?> safetyRatings} =>
1068- safetyRatings.map (_parseSafetyRating).toList (),
1069- _ => null
1070- },
1071- switch (jsonObject) {
1072- {'citationMetadata' : final Object citationMetadata} =>
1073- _parseCitationMetadata (citationMetadata),
1074- _ => null
1075- },
1076- switch (jsonObject) {
1077- {'finishReason' : final Object finishReason} =>
1078- FinishReason ._parseValue (finishReason),
1079- _ => null
1080- },
1081- switch (jsonObject) {
1082- {'finishMessage' : final String finishMessage} => finishMessage,
1083- _ => null
1084- },
1085- );
1211+ jsonObject.containsKey ('content' )
1212+ ? parseContent (jsonObject['content' ] as Object )
1213+ : Content (null , []),
1214+ switch (jsonObject) {
1215+ {'safetyRatings' : final List <Object ?> safetyRatings} =>
1216+ safetyRatings.map (_parseSafetyRating).toList (),
1217+ _ => null
1218+ },
1219+ switch (jsonObject) {
1220+ {'citationMetadata' : final Object citationMetadata} =>
1221+ _parseCitationMetadata (citationMetadata),
1222+ _ => null
1223+ },
1224+ switch (jsonObject) {
1225+ {'finishReason' : final Object finishReason} =>
1226+ FinishReason ._parseValue (finishReason),
1227+ _ => null
1228+ },
1229+ switch (jsonObject) {
1230+ {'finishMessage' : final String finishMessage} => finishMessage,
1231+ _ => null
1232+ },
1233+ groundingMetadata: switch (jsonObject) {
1234+ {'groundingMetadata' : final Object groundingMetadata} =>
1235+ _parseGroundingMetadata (groundingMetadata),
1236+ _ => null
1237+ });
10861238}
10871239
10881240PromptFeedback _parsePromptFeedback (Object jsonObject) {
@@ -1196,3 +1348,114 @@ Citation _parseCitationSource(Object? jsonObject) {
11961348 jsonObject['license' ] as String ? ,
11971349 );
11981350}
1351+
1352+ GroundingMetadata _parseGroundingMetadata (Object ? jsonObject) {
1353+ if (jsonObject is ! Map ) {
1354+ throw unhandledFormat ('GroundingMetadata' , jsonObject);
1355+ }
1356+
1357+ final searchEntryPoint = switch (jsonObject) {
1358+ {'searchEntryPoint' : final Object ? searchEntryPoint} =>
1359+ _parseSearchEntryPoint (searchEntryPoint),
1360+ _ => null ,
1361+ };
1362+ final groundingChunks = switch (jsonObject) {
1363+ {'groundingChunks' : final List <Object ?> groundingChunks} =>
1364+ groundingChunks.map (_parseGroundingChunk).toList (),
1365+ _ => null ,
1366+ } ??
1367+ [];
1368+ // Filters out null elements, which are returned from _parseGroundingSupport when
1369+ // segment is null.
1370+ final groundingSupport = switch (jsonObject) {
1371+ {'groundingSupport' : final List <Object ?> groundingSupport} =>
1372+ groundingSupport
1373+ .map (_parseGroundingSupport)
1374+ .whereType <GroundingSupport >()
1375+ .toList (),
1376+ _ => null ,
1377+ } ??
1378+ [];
1379+ final webSearchQueries = switch (jsonObject) {
1380+ {'webSearchQueries' : final List <String >? webSearchQueries} =>
1381+ webSearchQueries,
1382+ _ => null ,
1383+ } ??
1384+ [];
1385+
1386+ return GroundingMetadata (
1387+ searchEntryPoint: searchEntryPoint,
1388+ groundingChunks: groundingChunks,
1389+ groundingSupport: groundingSupport,
1390+ webSearchQueries: webSearchQueries);
1391+ }
1392+
1393+ Segment _parseSegment (Object ? jsonObject) {
1394+ if (jsonObject is ! Map ) {
1395+ throw unhandledFormat ('Segment' , jsonObject);
1396+ }
1397+
1398+ return Segment (
1399+ partIndex: (jsonObject['partIndex' ] as int ? ) ?? 0 ,
1400+ startIndex: (jsonObject['startIndex' ] as int ? ) ?? 0 ,
1401+ endIndex: (jsonObject['endIndex' ] as int ? ) ?? 0 ,
1402+ text: (jsonObject['text' ] as String ? ) ?? '' );
1403+ }
1404+
1405+ WebGroundingChunk _parseWebGroundingChunk (Object ? jsonObject) {
1406+ if (jsonObject is ! Map ) {
1407+ throw unhandledFormat ('WebGroundingChunk' , jsonObject);
1408+ }
1409+
1410+ return WebGroundingChunk (
1411+ uri: jsonObject['uri' ] as String ? ,
1412+ title: jsonObject['title' ] as String ? ,
1413+ domain: jsonObject['domain' ] as String ? ,
1414+ );
1415+ }
1416+
1417+ GroundingChunk _parseGroundingChunk (Object ? jsonObject) {
1418+ if (jsonObject is ! Map ) {
1419+ throw unhandledFormat ('GroundingChunk' , jsonObject);
1420+ }
1421+
1422+ return GroundingChunk (
1423+ web: jsonObject['web' ] != null
1424+ ? _parseWebGroundingChunk (jsonObject['web' ])
1425+ : null ,
1426+ );
1427+ }
1428+
1429+ GroundingSupport ? _parseGroundingSupport (Object ? jsonObject) {
1430+ if (jsonObject is ! Map ) {
1431+ throw unhandledFormat ('GroundingSupport' , jsonObject);
1432+ }
1433+
1434+ final segment = switch (jsonObject) {
1435+ {'segment' : final Object ? segment} => _parseSegment (segment),
1436+ _ => null ,
1437+ };
1438+ if (segment == null ) {
1439+ return null ;
1440+ }
1441+
1442+ return GroundingSupport (
1443+ segment: segment,
1444+ groundingChunkIndices:
1445+ (jsonObject['groundingChunkIndices' ] as List <int >? ) ?? []);
1446+ }
1447+
1448+ SearchEntryPoint _parseSearchEntryPoint (Object ? jsonObject) {
1449+ if (jsonObject is ! Map ) {
1450+ throw unhandledFormat ('SearchEntryPoint' , jsonObject);
1451+ }
1452+
1453+ final renderedContent = jsonObject['renderedContent' ] as String ? ;
1454+ if (renderedContent == null ) {
1455+ throw unhandledFormat ('SearchEntryPoint' , jsonObject);
1456+ }
1457+
1458+ return SearchEntryPoint (
1459+ renderedContent: renderedContent,
1460+ );
1461+ }
0 commit comments