diff --git a/src/Mscc.GenerativeAI/Enums/DynamicRetrievalConfigMode.cs b/src/Mscc.GenerativeAI/Enums/DynamicRetrievalConfigMode.cs
new file mode 100644
index 0000000..efcf6b1
--- /dev/null
+++ b/src/Mscc.GenerativeAI/Enums/DynamicRetrievalConfigMode.cs
@@ -0,0 +1,22 @@
+#if NET472_OR_GREATER || NETSTANDARD2_0
+using System.Text.Json.Serialization;
+#endif
+
+namespace Mscc.GenerativeAI
+{
+ ///
+ /// The mode of the predictor to be used in dynamic retrieval.
+ ///
+ [JsonConverter(typeof(JsonStringEnumConverter))]
+ public enum DynamicRetrievalConfigMode
+ {
+ ///
+ /// Always trigger retrieval.
+ ///
+ ModeUnspecified = 0,
+ ///
+ /// Run retrieval only when system decides it is necessary.
+ ///
+ ModeDynamic
+ }
+}
\ No newline at end of file
diff --git a/src/Mscc.GenerativeAI/Types/Generative/Candidate.cs b/src/Mscc.GenerativeAI/Types/Generative/Candidate.cs
index 9f92315..9bacb38 100644
--- a/src/Mscc.GenerativeAI/Types/Generative/Candidate.cs
+++ b/src/Mscc.GenerativeAI/Types/Generative/Candidate.cs
@@ -1,4 +1,6 @@
-using System.Collections.Generic;
+#if NET472_OR_GREATER || NETSTANDARD2_0
+using System.Collections.Generic;
+#endif
namespace Mscc.GenerativeAI
{
diff --git a/src/Mscc.GenerativeAI/Types/Generative/DynamicRetrievalConfig.cs b/src/Mscc.GenerativeAI/Types/Generative/DynamicRetrievalConfig.cs
new file mode 100644
index 0000000..ffc590c
--- /dev/null
+++ b/src/Mscc.GenerativeAI/Types/Generative/DynamicRetrievalConfig.cs
@@ -0,0 +1,17 @@
+namespace Mscc.GenerativeAI
+{
+ ///
+ /// Describes the options to customize dynamic retrieval.
+ ///
+ public class DynamicRetrievalConfig
+ {
+ ///
+ /// The mode of the predictor to be used in dynamic retrieval.
+ ///
+ public DynamicRetrievalConfigMode? Mode { get; set; }
+ ///
+ /// The threshold to be used in dynamic retrieval. If not set, a system default value is used.
+ ///
+ public float? DynamicThreshold { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Mscc.GenerativeAI/Types/Generative/GoogleSearchRetrieval.cs b/src/Mscc.GenerativeAI/Types/Generative/GoogleSearchRetrieval.cs
index b810c9f..f69b717 100644
--- a/src/Mscc.GenerativeAI/Types/Generative/GoogleSearchRetrieval.cs
+++ b/src/Mscc.GenerativeAI/Types/Generative/GoogleSearchRetrieval.cs
@@ -5,10 +5,33 @@ namespace Mscc.GenerativeAI
///
public class GoogleSearchRetrieval
{
+ ///
+ /// Specifies the dynamic retrieval configuration for the given source.
+ ///
+ public DynamicRetrievalConfig? DynamicRetrievalConfig { get; set; }
///
/// Optional. Disable using the result from this tool in detecting grounding attribution.
///
/// This does not affect how the result is given to the model for generation.
public bool? DisableAttribution { get; set; }
+
+ ///
+ /// Creates an instance of
+ ///
+ public GoogleSearchRetrieval() { }
+
+ ///
+ /// Creates an instance of with Mode and DynamicThreshold.
+ ///
+ /// The mode of the predictor to be used in dynamic retrieval.
+ /// The threshold to be used in dynamic retrieval. If not set, a system default value is used.
+ public GoogleSearchRetrieval(DynamicRetrievalConfigMode mode, float dynamicThreshold)
+ {
+ DynamicRetrievalConfig = new DynamicRetrievalConfig
+ {
+ Mode = mode,
+ DynamicThreshold = dynamicThreshold
+ };
+ }
}
}
\ No newline at end of file
diff --git a/src/Mscc.GenerativeAI/Types/Generative/GroundingChunk.cs b/src/Mscc.GenerativeAI/Types/Generative/GroundingChunk.cs
new file mode 100644
index 0000000..5e488b3
--- /dev/null
+++ b/src/Mscc.GenerativeAI/Types/Generative/GroundingChunk.cs
@@ -0,0 +1,13 @@
+namespace Mscc.GenerativeAI
+{
+ ///
+ /// Grounding chunk.
+ ///
+ public class GroundingChunk
+ {
+ ///
+ /// Grounding chunk from the web.
+ ///
+ public Web? Web { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Mscc.GenerativeAI/Types/Generative/GroundingMetadata.cs b/src/Mscc.GenerativeAI/Types/Generative/GroundingMetadata.cs
index 985a308..2e4102f 100644
--- a/src/Mscc.GenerativeAI/Types/Generative/GroundingMetadata.cs
+++ b/src/Mscc.GenerativeAI/Types/Generative/GroundingMetadata.cs
@@ -1,10 +1,37 @@
-using System.Collections.Generic;
+#if NET472_OR_GREATER || NETSTANDARD2_0
+using System.Collections.Generic;
+#endif
namespace Mscc.GenerativeAI
{
+ ///
+ /// Metadata returned to client when grounding is enabled.
+ ///
public class GroundingMetadata
{
+ ///
+ /// Optional. Google search entry for the following-up web searches.
+ ///
+ public SearchEntryPoint? SearchEntryPoint { get; set; }
+ ///
+ ///
+ ///
public List? GroundingAttributions { get; set; }
+ ///
+ /// Web search queries for the following-up web search.
+ ///
public List? WebSearchQueries { get; set; }
+ ///
+ /// List of grounding support.
+ ///
+ public List? GroundingSupports { get; set; }
+ ///
+ /// Metadata related to retrieval in the grounding flow.
+ ///
+ public RetrievalMetadata? RetrievalMetadata { get; set; }
+ ///
+ /// List of supporting references retrieved from specified grounding source.
+ ///
+ public List? GroundingChunks { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Mscc.GenerativeAI/Types/Generative/GroundingSupport.cs b/src/Mscc.GenerativeAI/Types/Generative/GroundingSupport.cs
new file mode 100644
index 0000000..0221c44
--- /dev/null
+++ b/src/Mscc.GenerativeAI/Types/Generative/GroundingSupport.cs
@@ -0,0 +1,29 @@
+#if NET472_OR_GREATER || NETSTANDARD2_0
+using System.Collections.Generic;
+#endif
+
+namespace Mscc.GenerativeAI
+{
+ ///
+ /// Grounding support.
+ ///
+ public class GroundingSupport
+ {
+ ///
+ /// Segment of the content this support belongs to.
+ ///
+ public Segment? Segment { get; set; }
+ ///
+ /// A list of indices (into 'grounding_chunk') specifying the citations associated with the claim.
+ ///
+ ///
+ /// For instance [1,3,4] means that grounding_chunk[1], grounding_chunk[3], grounding_chunk[4] are the retrieved content attributed to the claim.
+ ///
+ public List? GroundingChunkIndices { get; set; }
+ ///
+ /// Confidence score of the support references. Ranges from 0 to 1. 1 is the most confident.
+ /// This list must have the same size as the grounding_chunk_indices.
+ ///
+ public List? ConfidenceScores { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Mscc.GenerativeAI/Types/Generative/RetrievalMetadata.cs b/src/Mscc.GenerativeAI/Types/Generative/RetrievalMetadata.cs
new file mode 100644
index 0000000..6176b6b
--- /dev/null
+++ b/src/Mscc.GenerativeAI/Types/Generative/RetrievalMetadata.cs
@@ -0,0 +1,18 @@
+namespace Mscc.GenerativeAI
+{
+ ///
+ /// Metadata related to retrieval in the grounding flow.
+ ///
+ public class RetrievalMetadata
+ {
+ ///
+ /// Optional. Score indicating how likely information from google search could help answer the prompt.
+ ///
+ ///
+ /// The score is in the range [0, 1], where 0 is the least likely and 1 is the most likely.
+ /// This score is only populated when google search grounding and dynamic retrieval is enabled.
+ /// It will be compared to the threshold to determine whether to trigger google search.
+ ///
+ public float? GoogleSearchDynamicRetrievalScore { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Mscc.GenerativeAI/Types/Generative/SearchEntryPoint.cs b/src/Mscc.GenerativeAI/Types/Generative/SearchEntryPoint.cs
new file mode 100644
index 0000000..e6e7217
--- /dev/null
+++ b/src/Mscc.GenerativeAI/Types/Generative/SearchEntryPoint.cs
@@ -0,0 +1,17 @@
+namespace Mscc.GenerativeAI
+{
+ ///
+ /// Google search entry point.
+ ///
+ public class SearchEntryPoint
+ {
+ ///
+ /// Optional. Web content snippet that can be embedded in a web page or an app webview.
+ ///
+ public string? RenderedContent { get; set; }
+ ///
+ /// Optional. Base64 encoded JSON representing array of tuple.
+ ///
+ public byte[]? SdkBlob { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Mscc.GenerativeAI/Types/Generative/Segment.cs b/src/Mscc.GenerativeAI/Types/Generative/Segment.cs
new file mode 100644
index 0000000..a40f3ff
--- /dev/null
+++ b/src/Mscc.GenerativeAI/Types/Generative/Segment.cs
@@ -0,0 +1,25 @@
+namespace Mscc.GenerativeAI
+{
+ ///
+ /// Segment of the content.
+ ///
+ public class Segment
+ {
+ ///
+ /// Output only. The text corresponding to the segment from the response.
+ ///
+ public string? Text { get; set; }
+ ///
+ /// Output only. Start index in the given Part, measured in bytes. Offset from the start of the Part, inclusive, starting at zero.
+ ///
+ public int? StartIndex { get; set; }
+ ///
+ /// Output only. The index of a Part object within its parent Content object.
+ ///
+ public int? PartIndex { get; set; }
+ ///
+ /// Output only. End index in the given Part, measured in bytes. Offset from the start of the Part, exclusive, starting at zero.
+ ///
+ public int? EndIndex { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Mscc.GenerativeAI/Types/Generative/Web.cs b/src/Mscc.GenerativeAI/Types/Generative/Web.cs
new file mode 100644
index 0000000..7cba083
--- /dev/null
+++ b/src/Mscc.GenerativeAI/Types/Generative/Web.cs
@@ -0,0 +1,17 @@
+namespace Mscc.GenerativeAI
+{
+ ///
+ /// Chunk from the web.
+ ///
+ public class Web
+ {
+ ///
+ /// URI reference of the chunk.
+ ///
+ public string? Uri { get; set; }
+ ///
+ /// Title of the chunk.
+ ///
+ public string? Title { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/tests/Mscc.GenerativeAI/GoogleAi_GeminiPro_Should.cs b/tests/Mscc.GenerativeAI/GoogleAi_GeminiPro_Should.cs
index fc17648..7429d0c 100644
--- a/tests/Mscc.GenerativeAI/GoogleAi_GeminiPro_Should.cs
+++ b/tests/Mscc.GenerativeAI/GoogleAi_GeminiPro_Should.cs
@@ -771,7 +771,7 @@ public async Task Start_Chat_Streaming()
[Fact]
// Ref: https://ai.google.dev/api/generate-content#code-execution
- public async Task Code_Execution()
+ public async Task Generate_Content_Code_Execution()
{
// Arrange
var prompt = "What is the sum of the first 50 prime numbers?";
@@ -791,6 +791,72 @@ public async Task Code_Execution()
// .Where(t => !string.IsNullOrEmpty(t))
.ToArray()));
}
+
+ [Fact]
+ // Ref: https://ai.google.dev/gemini-api/docs/grounding
+ public async Task Generate_Content_Grounding_Search()
+ {
+ // Arrange
+ var prompt = "Who won Wimbledon this year?";
+ var genAi = new GoogleAI(_fixture.ApiKey);
+ var model = genAi.GenerativeModel("gemini-1.5-pro-002",
+ tools: [new Tool { GoogleSearchRetrieval = new() }]);
+
+ // Act
+ var response = await model.GenerateContent(prompt);
+
+ // Assert
+ response.Should().NotBeNull();
+ response.Candidates.Should().NotBeNull().And.HaveCount(1);
+ response.Candidates![0].GroundingMetadata.Should().NotBeNull();
+ response.Candidates![0].GroundingMetadata!.SearchEntryPoint.Should().NotBeNull();
+ response.Candidates![0].GroundingMetadata!.WebSearchQueries.Should().NotBeNull();
+ _output.WriteLine(string.Join(Environment.NewLine,
+ response.Candidates![0].Content!.Parts
+ .Select(x => x.Text)
+// .Where(t => !string.IsNullOrEmpty(t))
+ .ToArray()));
+ response.Candidates![0].GroundingMetadata!.GroundingChunks!
+ .ForEach(c =>
+ _output.WriteLine($"{c!.Web!.Title} - {c!.Web!.Uri}"));
+ _output.WriteLine(string.Join(Environment.NewLine,
+ response.Candidates![0].GroundingMetadata!.WebSearchQueries!
+ .Select(w => w)
+ .ToArray()));
+ _output.WriteLine(response.Candidates![0].GroundingMetadata!.SearchEntryPoint!.RenderedContent);
+ }
+
+ [Fact]
+ // Ref: https://ai.google.dev/gemini-api/docs/grounding
+ public async Task Generate_Content_Grounding_Search_Dictionary()
+ {
+ // Arrange
+ var prompt = "Who won Wimbledon this year?";
+ var genAi = new GoogleAI(_fixture.ApiKey);
+ var model = genAi.GenerativeModel("gemini-1.5-pro-002",
+ tools: [new Tool { GoogleSearchRetrieval =
+ new(DynamicRetrievalConfigMode.ModeUnspecified, 0.06f) }]);
+
+ // Act
+ var response = await model.GenerateContent(prompt);
+
+ // Assert
+ response.Should().NotBeNull();
+ response.Candidates.Should().NotBeNull().And.HaveCount(1);
+ _output.WriteLine(string.Join(Environment.NewLine,
+ response.Candidates![0].Content!.Parts
+ .Select(x => x.Text)
+// .Where(t => !string.IsNullOrEmpty(t))
+ .ToArray()));
+ response.Candidates![0].GroundingMetadata!.GroundingChunks!
+ .ForEach(c =>
+ _output.WriteLine($"{c!.Web!.Title} - {c!.Web!.Uri}"));
+ _output.WriteLine(string.Join(Environment.NewLine,
+ response.Candidates![0].GroundingMetadata!.WebSearchQueries!
+ .Select(w => w)
+ .ToArray()));
+ _output.WriteLine(response.Candidates![0].GroundingMetadata!.SearchEntryPoint!.RenderedContent);
+ }
[Fact]
// Ref: https://ai.google.dev/docs/function_calling