diff --git a/BotSharp.sln b/BotSharp.sln index 303f7320..d4890be1 100644 --- a/BotSharp.sln +++ b/BotSharp.sln @@ -125,6 +125,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Core.Crontab", "sr EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Core.Rules", "src\Infrastructure\BotSharp.Core.Rules\BotSharp.Core.Rules.csproj", "{AFD64412-4D6A-452E-82A2-79E5D8842E29}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.DeepSeekAI", "src\Plugins\BotSharp.Plugin.DeepSeekAI\BotSharp.Plugin.DeepSeekAI.csproj", "{AF329442-B48E-4B48-A18A-1C869D1BA6F5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -509,6 +511,14 @@ Global {AFD64412-4D6A-452E-82A2-79E5D8842E29}.Release|Any CPU.Build.0 = Release|Any CPU {AFD64412-4D6A-452E-82A2-79E5D8842E29}.Release|x64.ActiveCfg = Release|Any CPU {AFD64412-4D6A-452E-82A2-79E5D8842E29}.Release|x64.Build.0 = Release|Any CPU + {AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Debug|x64.ActiveCfg = Debug|Any CPU + {AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Debug|x64.Build.0 = Debug|Any CPU + {AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Release|Any CPU.Build.0 = Release|Any CPU + {AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Release|x64.ActiveCfg = Release|Any CPU + {AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -569,6 +579,7 @@ Global {7DA2DCD0-551B-432E-AA5C-22DDD3ED459B} = {D5293208-2BEF-42FC-A64C-5954F61720BA} {F812BAAE-5A7D-4DF7-8E71-70696B51C61F} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749} {AFD64412-4D6A-452E-82A2-79E5D8842E29} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749} + {AF329442-B48E-4B48-A18A-1C869D1BA6F5} = {D5293208-2BEF-42FC-A64C-5954F61720BA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19} diff --git a/src/Infrastructure/BotSharp.Abstraction/Statistics/Services/IBotSharpStatService.cs b/src/Infrastructure/BotSharp.Abstraction/Statistics/Services/IBotSharpStatsService.cs similarity index 83% rename from src/Infrastructure/BotSharp.Abstraction/Statistics/Services/IBotSharpStatService.cs rename to src/Infrastructure/BotSharp.Abstraction/Statistics/Services/IBotSharpStatsService.cs index 1fa8ba9e..bd520c9b 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Statistics/Services/IBotSharpStatService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Statistics/Services/IBotSharpStatsService.cs @@ -2,7 +2,7 @@ using BotSharp.Abstraction.Statistics.Models; namespace BotSharp.Abstraction.Statistics.Services; -public interface IBotSharpStatService +public interface IBotSharpStatsService { bool UpdateLlmCost(BotSharpStats stats); bool UpdateAgentCall(BotSharpStats stats); diff --git a/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs b/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs index d34dcd1f..e6998fe4 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs @@ -33,7 +33,7 @@ public class AgentPlugin : IBotSharpPlugin services.AddScoped(); services.AddScoped(); services.AddScoped(); - services.AddScoped(); + services.AddScoped(); services.AddScoped(provider => { diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/TokenStatistics.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/TokenStatistics.cs index a2b7d5be..7a8cef67 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/TokenStatistics.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/TokenStatistics.cs @@ -59,7 +59,7 @@ public class TokenStatistics : ITokenStatistics stat.SetState("llm_total_cost", total_cost, isNeedVersion: false, source: StateSource.Application); - var globalStats = _services.GetRequiredService(); + var globalStats = _services.GetRequiredService(); var body = new BotSharpStats { Category = StatCategory.LlmCost, diff --git a/src/Infrastructure/BotSharp.Core/Statistics/Services/BotSharpStatService.cs b/src/Infrastructure/BotSharp.Core/Statistics/Services/BotSharpStatsService.cs similarity index 95% rename from src/Infrastructure/BotSharp.Core/Statistics/Services/BotSharpStatService.cs rename to src/Infrastructure/BotSharp.Core/Statistics/Services/BotSharpStatsService.cs index d39b94bb..d70c7c24 100644 --- a/src/Infrastructure/BotSharp.Core/Statistics/Services/BotSharpStatService.cs +++ b/src/Infrastructure/BotSharp.Core/Statistics/Services/BotSharpStatsService.cs @@ -3,19 +3,19 @@ using BotSharp.Abstraction.Statistics.Settings; namespace BotSharp.Core.Statistics.Services; -public class BotSharpStatService : IBotSharpStatService +public class BotSharpStatsService : IBotSharpStatsService { private readonly IServiceProvider _services; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly StatisticsSettings _settings; private const string GLOBAL_LLM_COST = "global-llm-cost"; private const string GLOBAL_AGENT_CALL = "global-agent-call"; private const int TIMEOUT_SECONDS = 5; - public BotSharpStatService( + public BotSharpStatsService( IServiceProvider services, - ILogger logger, + ILogger logger, StatisticsSettings settings) { _services = services; diff --git a/src/Infrastructure/BotSharp.Logger/Hooks/GlobalStatsConversationHook.cs b/src/Infrastructure/BotSharp.Logger/Hooks/GlobalStatsConversationHook.cs index 79ba4115..2e7b115b 100644 --- a/src/Infrastructure/BotSharp.Logger/Hooks/GlobalStatsConversationHook.cs +++ b/src/Infrastructure/BotSharp.Logger/Hooks/GlobalStatsConversationHook.cs @@ -27,7 +27,7 @@ public class GlobalStatsConversationHook : ConversationHookBase private void UpdateAgentCall(RoleDialogModel message) { // record agent call - var globalStats = _services.GetRequiredService(); + var globalStats = _services.GetRequiredService(); var body = new BotSharpStats { diff --git a/src/Plugins/BotSharp.Plugin.DeepSeekAI/BotSharp.Plugin.DeepSeekAI.csproj b/src/Plugins/BotSharp.Plugin.DeepSeekAI/BotSharp.Plugin.DeepSeekAI.csproj new file mode 100644 index 00000000..56eb14ef --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.DeepSeekAI/BotSharp.Plugin.DeepSeekAI.csproj @@ -0,0 +1,21 @@ + + + + $(TargetFramework) + enable + $(LangVersion) + $(BotSharpVersion) + $(GeneratePackageOnBuild) + $(GenerateDocumentationFile) + $(SolutionDir)packages + + + + + + + + + + + diff --git a/src/Plugins/BotSharp.Plugin.DeepSeekAI/DeepSeekAiPlugin.cs b/src/Plugins/BotSharp.Plugin.DeepSeekAI/DeepSeekAiPlugin.cs new file mode 100644 index 00000000..063d1ad1 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.DeepSeekAI/DeepSeekAiPlugin.cs @@ -0,0 +1,18 @@ +using BotSharp.Abstraction.Plugins; +using BotSharp.Plugin.DeepSeek.Providers.Text; +using BotSharp.Plugin.DeepSeekAI.Providers.Chat; + +namespace BotSharp.Plugin.DeepSeek; + +public class DeepSeekAiPlugin : IBotSharpPlugin +{ + public string Id => "1f0e73a5-bcaa-44e9-adde-e46cd94d244b"; + public string Name => "DeepSeek"; + public string Description => "DeepSeek AI"; + public string IconUrl => "https://cdn.deepseek.com/logo.png"; + public void RegisterDI(IServiceCollection services, IConfiguration config) + { + services.AddScoped(); + services.AddScoped(); + } +} diff --git a/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/Chat/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/Chat/ChatCompletionProvider.cs new file mode 100644 index 00000000..a7c6b48d --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/Chat/ChatCompletionProvider.cs @@ -0,0 +1,337 @@ +using Microsoft.Extensions.Logging; +using OpenAI.Chat; +using BotSharp.Abstraction.Files; +using BotSharp.Plugin.DeepSeek.Providers; + +namespace BotSharp.Plugin.DeepSeekAI.Providers.Chat; + +public class ChatCompletionProvider : IChatCompletion +{ + protected readonly IServiceProvider _services; + protected readonly ILogger _logger; + + protected string _model; + public virtual string Provider => "deepseek-ai"; + + public ChatCompletionProvider( + 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.GetClient(Provider, _model, _services); + var chatClient = client.GetChatClient(_model); + var (prompt, messages, options) = PrepareOptions(agent, conversations); + + var response = chatClient.CompleteChat(messages, options); + var value = response.Value; + var reason = value.FinishReason; + var content = value.Content; + var text = content.FirstOrDefault()?.Text ?? string.Empty; + + RoleDialogModel responseMessage; + if (reason == ChatFinishReason.FunctionCall || reason == ChatFinishReason.ToolCalls) + { + var toolCall = value.ToolCalls.FirstOrDefault(); + responseMessage = new RoleDialogModel(AgentRole.Function, text) + { + CurrentAgentId = agent.Id, + MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty, + ToolCallId = toolCall?.Id, + FunctionName = toolCall?.FunctionName, + FunctionArgs = toolCall?.FunctionArguments?.ToString() + }; + + // Somethings LLM will generate a function name with agent name. + if (!string.IsNullOrEmpty(responseMessage.FunctionName)) + { + responseMessage.FunctionName = responseMessage.FunctionName.Split('.').Last(); + } + } + 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, + PromptCount = response.Value?.Usage?.InputTokenCount ?? 0, + CompletionCount = response.Value?.Usage?.OutputTokenCount ?? 0 + }); + } + + return responseMessage; + } + + public async Task GetChatCompletionsAsync(Agent agent, List conversations, Func onMessageReceived, Func onFunctionExecuting) + { + var hooks = _services.GetServices().ToList(); + + // Before chat completion hook + foreach (var hook in hooks) + { + await hook.BeforeGenerating(agent, conversations); + } + + var client = ProviderHelper.GetClient(Provider, _model, _services); + var chatClient = client.GetChatClient(_model); + var (prompt, messages, options) = PrepareOptions(agent, conversations); + + var response = await chatClient.CompleteChatAsync(messages, options); + var value = response.Value; + var reason = value.FinishReason; + var content = value.Content; + var text = content.FirstOrDefault()?.Text ?? string.Empty; + + var msg = new RoleDialogModel(AgentRole.Assistant, text) + { + CurrentAgentId = agent.Id + }; + + // After chat completion hook + foreach (var hook in hooks) + { + await hook.AfterGenerated(msg, new TokenStatsModel + { + Prompt = prompt, + Provider = Provider, + Model = _model, + PromptCount = response.Value?.Usage?.InputTokenCount ?? 0, + CompletionCount = response.Value?.Usage?.OutputTokenCount ?? 0 + }); + } + + if (reason == ChatFinishReason.FunctionCall || reason == ChatFinishReason.ToolCalls) + { + var toolCall = value.ToolCalls?.FirstOrDefault(); + _logger.LogInformation($"[{agent.Name}]: {toolCall?.FunctionName}({toolCall?.FunctionArguments})"); + + var funcContextIn = new RoleDialogModel(AgentRole.Function, text) + { + CurrentAgentId = agent.Id, + MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty, + ToolCallId = toolCall?.Id, + FunctionName = toolCall?.FunctionName, + FunctionArgs = toolCall?.FunctionArguments?.ToString() + }; + + // Somethings LLM will generate a function name with agent name. + if (!string.IsNullOrEmpty(funcContextIn.FunctionName)) + { + funcContextIn.FunctionName = funcContextIn.FunctionName.Split('.').Last(); + } + + // Execute functions + await onFunctionExecuting(funcContextIn); + } + else + { + // Text response received + await onMessageReceived(msg); + } + + return true; + } + + public async Task GetChatCompletionsStreamingAsync(Agent agent, List conversations, Func onMessageReceived) + { + var client = ProviderHelper.GetClient(Provider, _model, _services); + var chatClient = client.GetChatClient(_model); + var (prompt, messages, options) = PrepareOptions(agent, conversations); + + var response = chatClient.CompleteChatStreamingAsync(messages, options); + + await foreach (var choice in response) + { + if (choice.FinishReason == ChatFinishReason.FunctionCall || choice.FinishReason == ChatFinishReason.ToolCalls) + { + var update = choice.ToolCallUpdates?.FirstOrDefault()?.FunctionArgumentsUpdate?.ToString() ?? string.Empty; + _logger.LogInformation(update); + + await onMessageReceived(new RoleDialogModel(AgentRole.Assistant, update)); + continue; + } + + if (choice.ContentUpdate.IsNullOrEmpty()) continue; + + _logger.LogInformation(choice.ContentUpdate[0]?.Text); + + await onMessageReceived(new RoleDialogModel(choice.Role?.ToString() ?? ChatMessageRole.Assistant.ToString(), choice.ContentUpdate[0]?.Text ?? string.Empty)); + } + + return true; + } + + public void SetModelName(string model) + { + _model = model; + } + + protected (string, IEnumerable, ChatCompletionOptions) PrepareOptions(Agent agent, List conversations) + { + var agentService = _services.GetRequiredService(); + var state = _services.GetRequiredService(); + var fileStorage = _services.GetRequiredService(); + var settingsService = _services.GetRequiredService(); + var settings = settingsService.GetSetting(Provider, _model); + var allowMultiModal = settings != null && settings.MultiModal; + + var messages = new List(); + + var temperature = float.Parse(state.GetState("temperature", "0.0")); + var maxTokens = int.Parse(state.GetState("max_tokens", "1024")); + var options = new ChatCompletionOptions() + { + Temperature = temperature, + MaxOutputTokenCount = maxTokens + }; + + var functions = agent.Functions.Concat(agent.SecondaryFunctions ?? []); + foreach (var function in functions) + { + if (!agentService.RenderFunction(agent, function)) continue; + + var property = agentService.RenderFunctionProperty(agent, function); + + options.Tools.Add(ChatTool.CreateFunctionTool( + functionName: function.Name, + functionDescription: function.Description, + functionParameters: BinaryData.FromObjectAsJson(property))); + } + + if (!string.IsNullOrEmpty(agent.Instruction) || !agent.SecondaryInstructions.IsNullOrEmpty()) + { + var text = agentService.RenderedInstruction(agent); + messages.Add(new SystemChatMessage(text)); + } + + if (!string.IsNullOrEmpty(agent.Knowledges)) + { + messages.Add(new SystemChatMessage(agent.Knowledges)); + } + + var filteredMessages = conversations.Select(x => x).ToList(); + var firstUserMsgIdx = filteredMessages.FindIndex(x => x.Role == AgentRole.User); + if (firstUserMsgIdx > 0) + { + filteredMessages = filteredMessages.Where((_, idx) => idx >= firstUserMsgIdx).ToList(); + } + + foreach (var message in filteredMessages) + { + if (message.Role == AgentRole.Function) + { + messages.Add(new AssistantChatMessage(new List + { + ChatToolCall.CreateFunctionToolCall(message.ToolCallId, message.FunctionName, BinaryData.FromString(message.FunctionArgs ?? string.Empty)) + })); + + messages.Add(new ToolChatMessage(message.ToolCallId, message.Content)); + } + else if (message.Role == AgentRole.User) + { + var text = !string.IsNullOrWhiteSpace(message.Payload) ? message.Payload : message.Content; + var textPart = ChatMessageContentPart.CreateTextPart(text); + var contentParts = new List { textPart }; + messages.Add(new UserChatMessage(contentParts)); + } + else if (message.Role == AgentRole.Assistant) + { + messages.Add(new AssistantChatMessage(message.Content)); + } + } + + var prompt = GetPrompt(messages, options); + return (prompt, messages, options); + } + + + private string GetPrompt(IEnumerable messages, ChatCompletionOptions options) + { + var prompt = string.Empty; + + if (!messages.IsNullOrEmpty()) + { + // System instruction + var verbose = string.Join("\r\n", messages + .Select(x => x as SystemChatMessage) + .Where(x => x != null) + .Select(x => + { + if (!string.IsNullOrEmpty(x.ParticipantName)) + { + // To display Agent name in log + return $"[{x.ParticipantName}]: {x.Content.FirstOrDefault()?.Text ?? string.Empty}"; + } + return $"{AgentRole.System}: {x.Content.FirstOrDefault()?.Text ?? string.Empty}"; + })); + prompt += $"{verbose}\r\n"; + + prompt += "\r\n[CONVERSATION]"; + verbose = string.Join("\r\n", messages + .Where(x => x as SystemChatMessage == null) + .Select(x => + { + var fnMessage = x as ToolChatMessage; + if (fnMessage != null) + { + return $"{AgentRole.Function}: {fnMessage.Content.FirstOrDefault()?.Text ?? string.Empty}"; + } + + var userMessage = x as UserChatMessage; + if (userMessage != null) + { + var content = x.Content.FirstOrDefault()?.Text ?? string.Empty; + return !string.IsNullOrEmpty(userMessage.ParticipantName) && userMessage.ParticipantName != "route_to_agent" ? + $"{userMessage.ParticipantName}: {content}" : + $"{AgentRole.User}: {content}"; + } + + var assistMessage = x as AssistantChatMessage; + if (assistMessage != null) + { + var toolCall = assistMessage.ToolCalls?.FirstOrDefault(); + return toolCall != null ? + $"{AgentRole.Assistant}: Call function {toolCall?.FunctionName}({toolCall?.FunctionArguments})" : + $"{AgentRole.Assistant}: {assistMessage.Content.FirstOrDefault()?.Text ?? string.Empty}"; + } + + return string.Empty; + })); + prompt += $"\r\n{verbose}\r\n"; + } + + if (!options.Tools.IsNullOrEmpty()) + { + var functions = string.Join("\r\n", options.Tools.Select(fn => + { + return $"\r\n{fn.FunctionName}: {fn.FunctionDescription}\r\n{fn.FunctionParameters}"; + })); + prompt += $"\r\n[FUNCTIONS]{functions}\r\n"; + } + + return prompt; + } +} diff --git a/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/ProviderHelper.cs b/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/ProviderHelper.cs new file mode 100644 index 00000000..acd6653b --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/ProviderHelper.cs @@ -0,0 +1,16 @@ +using OpenAI; +using System.ClientModel; + +namespace BotSharp.Plugin.DeepSeek.Providers; + +public static class ProviderHelper +{ + public static OpenAIClient GetClient(string provider, string model, IServiceProvider services) + { + var settingsService = services.GetRequiredService(); + var settings = settingsService.GetSetting(provider, model); + var options = !string.IsNullOrEmpty(settings.Endpoint) ? + new OpenAIClientOptions { Endpoint = new Uri(settings.Endpoint) } : null; + return new OpenAIClient(new ApiKeyCredential(settings.ApiKey), options); + } +} diff --git a/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/Text/TextCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/Text/TextCompletionProvider.cs new file mode 100644 index 00000000..a1a88978 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/Text/TextCompletionProvider.cs @@ -0,0 +1,95 @@ +using Microsoft.Extensions.Logging; +using OpenAI.Chat; + +namespace BotSharp.Plugin.DeepSeek.Providers.Text; + +public class TextCompletionProvider : ITextCompletion +{ + private readonly IServiceProvider _services; + private readonly ILogger _logger; + protected string _model; + + public string Provider => "deepseek-ai"; + + public TextCompletionProvider( + IServiceProvider services, + ILogger logger) + { + _services = services; + _logger = logger; + } + + public async Task GetCompletion(string text, string agentId, string messageId) + { + var contentHooks = _services.GetServices().ToList(); + var state = _services.GetRequiredService(); + + // Before chat completion hook + var agent = new Agent() + { + Id = agentId, + }; + var message = new RoleDialogModel(AgentRole.User, text) + { + CurrentAgentId = agentId, + MessageId = messageId + }; + + foreach (var hook in contentHooks) + { + await hook.BeforeGenerating(agent, new List { message }); + } + + var client = ProviderHelper.GetClient(Provider, _model, _services); + var chatClient = client.GetChatClient(_model); + var options = PrepareOptions(); + var response = chatClient.CompleteChat([ new UserChatMessage(text) ], options); + + // AI response + var content = response.Value?.Content ?? []; + var completion = string.Empty; + foreach (var t in content) + { + completion += t?.Text ?? string.Empty; + }; + + // After chat completion hook + var responseMessage = new RoleDialogModel(AgentRole.Assistant, completion) + { + CurrentAgentId = agentId, + MessageId = messageId + }; + + foreach (var hook in contentHooks) + { + await hook.AfterGenerated(responseMessage, new TokenStatsModel + { + Prompt = text, + Provider = Provider, + Model = _model, + PromptCount = response?.Value?.Usage?.InputTokenCount ?? default, + CompletionCount = response?.Value?.Usage?.OutputTokenCount ?? default + }); + } + + return completion.Trim(); + } + + public void SetModelName(string model) + { + _model = model; + } + + private ChatCompletionOptions PrepareOptions() + { + var state = _services.GetRequiredService(); + var temperature = float.Parse(state.GetState("temperature", "0.0")); + var maxTokens = int.Parse(state.GetState("max_tokens", "1024")); + + return new ChatCompletionOptions + { + Temperature = temperature, + MaxOutputTokenCount = maxTokens + }; + } +} diff --git a/src/Plugins/BotSharp.Plugin.DeepSeekAI/Using.cs b/src/Plugins/BotSharp.Plugin.DeepSeekAI/Using.cs new file mode 100644 index 00000000..a16dcc87 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.DeepSeekAI/Using.cs @@ -0,0 +1,19 @@ +global using System; +global using System.Collections.Generic; +global using System.Text; +global using System.Threading.Tasks; +global using System.Linq; +global using System.Text.Json; +global using Microsoft.Extensions.Configuration; +global using Microsoft.Extensions.DependencyInjection; +global using DeepSeek.Core; +global using BotSharp.Abstraction.Conversations.Models; +global using BotSharp.Abstraction.Agents.Models; +global using BotSharp.Abstraction.MLTasks; +global using BotSharp.Abstraction.Agents; +global using BotSharp.Abstraction.Agents.Enums; +global using BotSharp.Abstraction.Conversations; +global using BotSharp.Abstraction.Loggers; +global using BotSharp.Abstraction.Functions.Models; +global using BotSharp.Abstraction.Utilities; +global using BotSharp.Plugin.DeepSeekAI.Models; \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Chat/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Chat/ChatCompletionProvider.cs index 21756f5d..e8f12ec7 100644 --- a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Chat/ChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Chat/ChatCompletionProvider.cs @@ -1,7 +1,5 @@ using BotSharp.Abstraction.Files.Utilities; -using BotSharp.Abstraction.Templating; using OpenAI.Chat; -using static System.Net.Mime.MediaTypeNames; namespace BotSharp.Plugin.OpenAI.Providers.Chat; @@ -254,10 +252,10 @@ public class ChatCompletionProvider : IChatCompletion { messages.Add(new AssistantChatMessage(new List { - ChatToolCall.CreateFunctionToolCall(message.FunctionName, message.FunctionName, BinaryData.FromString(message.FunctionArgs ?? string.Empty)) + ChatToolCall.CreateFunctionToolCall(message.ToolCallId, message.FunctionName, BinaryData.FromString(message.FunctionArgs ?? string.Empty)) })); - messages.Add(new ToolChatMessage(message.FunctionName, message.Content)); + messages.Add(new ToolChatMessage(message.ToolCallId, message.Content)); } else if (message.Role == AgentRole.User) { diff --git a/src/WebStarter/WebStarter.csproj b/src/WebStarter/WebStarter.csproj index 4ecedf9e..b2fcd816 100644 --- a/src/WebStarter/WebStarter.csproj +++ b/src/WebStarter/WebStarter.csproj @@ -45,6 +45,7 @@ + diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json index c5ea7db1..a85a88a7 100644 --- a/src/WebStarter/appsettings.json +++ b/src/WebStarter/appsettings.json @@ -348,6 +348,7 @@ "BotSharp.Plugin.AnthropicAI", "BotSharp.Plugin.GoogleAI", "BotSharp.Plugin.MetaAI", + "BotSharp.Plugin.DeepSeekAI", "BotSharp.Plugin.MetaMessenger", "BotSharp.Plugin.HuggingFace", "BotSharp.Plugin.KnowledgeBase",