diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentRole.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentRole.cs
index f9547d5a..226313e0 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentRole.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentRole.cs
@@ -6,4 +6,5 @@ public class AgentRole
public const string Assistant = "assistant";
public const string User = "user";
public const string Function = "function";
+ public const string Model = "model";
}
diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/Chat/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/Chat/ChatCompletionProvider.cs
index 3384e3b7..a1684c9d 100644
--- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/Chat/ChatCompletionProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/Chat/ChatCompletionProvider.cs
@@ -290,20 +290,20 @@ public class ChatCompletionProvider : IChatCompletion
if (!string.IsNullOrEmpty(file.FileData))
{
var (contentType, bytes) = FileUtility.GetFileInfoFromData(file.FileData);
- var contentPart = ChatMessageContentPart.CreateImagePart(BinaryData.FromBytes(bytes), contentType, ChatImageDetailLevel.Low);
+ var contentPart = ChatMessageContentPart.CreateImagePart(BinaryData.FromBytes(bytes), contentType, ChatImageDetailLevel.Auto);
contentParts.Add(contentPart);
}
else if (!string.IsNullOrEmpty(file.FileStorageUrl))
{
var contentType = FileUtility.GetFileContentType(file.FileStorageUrl);
var bytes = fileStorage.GetFileBytes(file.FileStorageUrl);
- var contentPart = ChatMessageContentPart.CreateImagePart(BinaryData.FromBytes(bytes), contentType, ChatImageDetailLevel.Low);
+ var contentPart = ChatMessageContentPart.CreateImagePart(BinaryData.FromBytes(bytes), contentType, ChatImageDetailLevel.Auto);
contentParts.Add(contentPart);
}
else if (!string.IsNullOrEmpty(file.FileUrl))
{
var uri = new Uri(file.FileUrl);
- var contentPart = ChatMessageContentPart.CreateImagePart(uri, ChatImageDetailLevel.Low);
+ var contentPart = ChatMessageContentPart.CreateImagePart(uri, ChatImageDetailLevel.Auto);
contentParts.Add(contentPart);
}
}
diff --git a/src/Plugins/BotSharp.Plugin.GoogleAI/BotSharp.Plugin.GoogleAI.csproj b/src/Plugins/BotSharp.Plugin.GoogleAI/BotSharp.Plugin.GoogleAI.csproj
index 93c0f9df..b6e0b24e 100644
--- a/src/Plugins/BotSharp.Plugin.GoogleAI/BotSharp.Plugin.GoogleAI.csproj
+++ b/src/Plugins/BotSharp.Plugin.GoogleAI/BotSharp.Plugin.GoogleAI.csproj
@@ -12,6 +12,7 @@
+
diff --git a/src/Plugins/BotSharp.Plugin.GoogleAI/GoogleAiPlugin.cs b/src/Plugins/BotSharp.Plugin.GoogleAI/GoogleAiPlugin.cs
index aac88308..58a384a7 100644
--- a/src/Plugins/BotSharp.Plugin.GoogleAI/GoogleAiPlugin.cs
+++ b/src/Plugins/BotSharp.Plugin.GoogleAI/GoogleAiPlugin.cs
@@ -1,9 +1,9 @@
using BotSharp.Abstraction.Plugins;
using BotSharp.Abstraction.Settings;
-using BotSharp.Plugin.GoogleAI.Providers;
-using BotSharp.Plugin.GoogleAI.Settings;
+using BotSharp.Plugin.GoogleAi.Providers.Chat;
+using BotSharp.Plugin.GoogleAi.Providers.Text;
-namespace BotSharp.Plugin.GoogleAI;
+namespace BotSharp.Plugin.GoogleAi;
public class GoogleAiPlugin : IBotSharpPlugin
{
@@ -19,7 +19,9 @@ public class GoogleAiPlugin : IBotSharpPlugin
return settingService.Bind("GoogleAi");
});
- services.AddScoped();
- services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
}
}
diff --git a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/GeminiChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/GeminiChatCompletionProvider.cs
new file mode 100644
index 00000000..4419048b
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/GeminiChatCompletionProvider.cs
@@ -0,0 +1,217 @@
+using BotSharp.Abstraction.Agents;
+using BotSharp.Abstraction.Agents.Enums;
+using BotSharp.Abstraction.Loggers;
+using Microsoft.Extensions.Logging;
+using Mscc.GenerativeAI;
+
+namespace BotSharp.Plugin.GoogleAi.Providers.Chat;
+
+public class GeminiChatCompletionProvider : IChatCompletion
+{
+ private readonly IServiceProvider _services;
+ private readonly ILogger _logger;
+
+ private string _model;
+
+ public string Provider => "google-gemini";
+
+ public GeminiChatCompletionProvider(
+ IServiceProvider services,
+ ILogger logger)
+ {
+ _services = services;
+ _logger = logger;
+ }
+
+ public async Task GetChatCompletions(Agent agent, List conversations)
+ {
+ var contentHooks = _services.GetServices().ToList();
+
+ // Before chat completion hook
+ foreach (var hook in contentHooks)
+ {
+ await hook.BeforeGenerating(agent, conversations);
+ }
+
+ var client = ProviderHelper.GetGeminiClient(_services);
+ var aiModel = client.GenerativeModel(_model);
+ var (prompt, request) = PrepareOptions(aiModel, agent, conversations);
+
+ var response = await aiModel.GenerateContent(request);
+ var candidate = response.Candidates.First();
+ var part = candidate.Content?.Parts?.FirstOrDefault();
+ var text = part?.Text ?? string.Empty;
+
+ RoleDialogModel responseMessage;
+ if (part?.FunctionCall != null)
+ {
+ responseMessage = new RoleDialogModel(AgentRole.Function, text)
+ {
+ CurrentAgentId = agent.Id,
+ MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
+ ToolCallId = part.FunctionCall.Name,
+ FunctionName = part.FunctionCall.Name,
+ FunctionArgs = part.FunctionCall.Args?.ToString()
+ };
+ }
+ else
+ {
+ responseMessage = new RoleDialogModel(AgentRole.Assistant, text)
+ {
+ CurrentAgentId = agent.Id,
+ MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
+ };
+ }
+
+ // After chat completion hook
+ foreach (var hook in contentHooks)
+ {
+ await hook.AfterGenerated(responseMessage, new TokenStatsModel
+ {
+ Prompt = prompt,
+ Provider = Provider,
+ Model = _model
+ });
+ }
+
+ return responseMessage;
+ }
+
+ public Task GetChatCompletionsAsync(Agent agent, List conversations, Func onMessageReceived, Func onFunctionExecuting)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task GetChatCompletionsStreamingAsync(Agent agent, List conversations, Func onMessageReceived)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void SetModelName(string model)
+ {
+ _model = model;
+ }
+
+ private (string, GenerateContentRequest) PrepareOptions(GenerativeModel aiModel, Agent agent, List conversations)
+ {
+ var agentService = _services.GetRequiredService();
+ var googleSettings = _services.GetRequiredService();
+
+ // Add settings
+ aiModel.UseGoogleSearch = googleSettings.Gemini.UseGoogleSearch;
+ aiModel.UseGrounding = googleSettings.Gemini.UseGrounding;
+
+ // Assembly messages
+ var contents = new List();
+ var tools = new List();
+ var funcDeclarations = new List();
+
+ var systemPrompts = new List();
+ if (!string.IsNullOrEmpty(agent.Instruction))
+ {
+ var instruction = agentService.RenderedInstruction(agent);
+ contents.Add(new Content(instruction)
+ {
+ Role = AgentRole.User
+ });
+
+ systemPrompts.Add(instruction);
+ }
+
+ var funcPrompts = new List();
+ foreach (var function in agent.Functions)
+ {
+ if (!agentService.RenderFunction(agent, function)) continue;
+
+ var def = agentService.RenderFunctionProperty(agent, function);
+
+ funcDeclarations.Add(new FunctionDeclaration
+ {
+ Name = function.Name,
+ Description = function.Description,
+ Parameters = new()
+ {
+ Type = ParameterType.Object,
+ Properties = def.Properties,
+ Required = def.Required
+ }
+ });
+
+ funcPrompts.Add($"{function.Name}: {function.Description} {def}");
+ }
+
+ if (!funcDeclarations.IsNullOrEmpty())
+ {
+ tools.Add(new Tool { FunctionDeclarations = funcDeclarations });
+ }
+
+ var convPrompts = new List();
+ foreach (var message in conversations)
+ {
+ if (message.Role == AgentRole.Function)
+ {
+ contents.Add(new Content(message.Content)
+ {
+ Role = AgentRole.Function,
+ Parts = new()
+ {
+ new FunctionCall
+ {
+ Name = message.FunctionName,
+ Args = JsonSerializer.Deserialize