diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/MCPTool.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/MCPTool.cs index 88e2d4b05..ee8e52d41 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/MCPTool.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/MCPTool.cs @@ -2,9 +2,16 @@ namespace BotSharp.Abstraction.Agents.Models; public class McpTool { + [JsonPropertyName("name")] public string Name { get; set; } + + [JsonPropertyName("server_id")] public string ServerId { get; set; } + + [JsonPropertyName("disabled")] public bool Disabled { get; set; } + + [JsonPropertyName("functions")] public IEnumerable Functions { get; set; } = []; public McpTool() diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Models/SelectFileOptions.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Models/SelectFileOptions.cs index d61c1b7c3..29a1c9ea9 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Files/Models/SelectFileOptions.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Files/Models/SelectFileOptions.cs @@ -8,9 +8,9 @@ public class SelectFileOptions public string? Provider { get; set; } /// - /// Llm model id + /// Llm model /// - public string? ModelId { get; set; } + public string? Model { get; set; } /// /// Agent id diff --git a/src/Infrastructure/BotSharp.Core.MCP/BotSharpMCPExtensions.cs b/src/Infrastructure/BotSharp.Core.MCP/BotSharpMCPExtensions.cs index 0f6c3a8fb..1a6ff235e 100644 --- a/src/Infrastructure/BotSharp.Core.MCP/BotSharpMCPExtensions.cs +++ b/src/Infrastructure/BotSharp.Core.MCP/BotSharpMCPExtensions.cs @@ -18,9 +18,9 @@ public static class BotSharpMcpExtensions /// public static IServiceCollection AddBotSharpMCP(this IServiceCollection services, IConfiguration config) { - var settings = config.GetSection("MCPSettings").Get(); - services.AddScoped(provider => { return settings; }); - if (settings != null && !settings.McpServerConfigs.IsNullOrEmpty()) + var settings = config.GetSection("MCP").Get(); + services.AddScoped(provider => { return settings; }); + if (settings != null && settings.Enabled && !settings.McpServerConfigs.IsNullOrEmpty()) { var clientManager = new McpClientManager(settings); services.AddSingleton(clientManager); diff --git a/src/Infrastructure/BotSharp.Core.MCP/Hooks/MCPToolAgentHook.cs b/src/Infrastructure/BotSharp.Core.MCP/Hooks/MCPToolAgentHook.cs index 40a59e2b3..c0ccaaaba 100644 --- a/src/Infrastructure/BotSharp.Core.MCP/Hooks/MCPToolAgentHook.cs +++ b/src/Infrastructure/BotSharp.Core.MCP/Hooks/MCPToolAgentHook.cs @@ -1,5 +1,6 @@ using BotSharp.Core.MCP.Helpers; using BotSharp.Core.MCP.Managers; +using BotSharp.Core.MCP.Settings; using ModelContextProtocol.Client; namespace BotSharp.Core.MCP.Hooks; @@ -39,6 +40,13 @@ public override void OnAgentMcpToolLoaded(Agent agent) private async Task> GetMcpContent(Agent agent) { var functionDefs = new List(); + + var settings = _services.GetRequiredService(); + if (settings?.Enabled != true) + { + return functionDefs; + } + var mcpClientManager = _services.GetRequiredService(); var mcps = agent.McpTools.Where(x => !x.Disabled); foreach (var item in mcps) diff --git a/src/Infrastructure/BotSharp.Core.MCP/Managers/McpClientManager.cs b/src/Infrastructure/BotSharp.Core.MCP/Managers/McpClientManager.cs index 523e4b006..c11163b38 100644 --- a/src/Infrastructure/BotSharp.Core.MCP/Managers/McpClientManager.cs +++ b/src/Infrastructure/BotSharp.Core.MCP/Managers/McpClientManager.cs @@ -5,19 +5,18 @@ namespace BotSharp.Core.MCP.Managers; public class McpClientManager : IDisposable { + private readonly McpSettings _mcpSettings; - private readonly McpSettings mcpSettings; - - public McpClientManager(McpSettings settings) + public McpClientManager(McpSettings mcpSettings) { - mcpSettings = settings; + _mcpSettings = mcpSettings; } public async Task GetMcpClientAsync(string serverId) { return await McpClientFactory.CreateAsync( - mcpSettings.McpServerConfigs.Where(x=> x.Name == serverId).First(), - mcpSettings.McpClientOptions); + _mcpSettings.McpServerConfigs.Where(x=> x.Name == serverId).First(), + _mcpSettings.McpClientOptions); } public void Dispose() diff --git a/src/Infrastructure/BotSharp.Core.MCP/McpPlugin.cs b/src/Infrastructure/BotSharp.Core.MCP/McpPlugin.cs new file mode 100644 index 000000000..3b7dfd571 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core.MCP/McpPlugin.cs @@ -0,0 +1,29 @@ +using BotSharp.Abstraction.Plugins.Models; +using BotSharp.Abstraction.Plugins; +using BotSharp.Abstraction.Settings; +using BotSharp.Core.MCP.Settings; +using Microsoft.Extensions.Configuration; + +namespace BotSharp.Core.MCP; + +public class McpPlugin : IBotSharpPlugin +{ + public string Id => "0cfb486a-229e-4470-a4c6-d2d4a5fdc727"; + public string Name => "Model context protocol"; + public string Description => "Model context protocol"; + + public SettingsMeta Settings => + new SettingsMeta("MCP"); + + public object GetNewSettingsInstance() => + new McpSettings(); + + public void RegisterDI(IServiceCollection services, IConfiguration config) + { + } + + public bool AttachMenu(List menu) + { + return true; + } +} diff --git a/src/Infrastructure/BotSharp.Core.MCP/Settings/MCPSettings.cs b/src/Infrastructure/BotSharp.Core.MCP/Settings/MCPSettings.cs index 09884f2bd..364b0a917 100644 --- a/src/Infrastructure/BotSharp.Core.MCP/Settings/MCPSettings.cs +++ b/src/Infrastructure/BotSharp.Core.MCP/Settings/MCPSettings.cs @@ -5,6 +5,7 @@ namespace BotSharp.Core.MCP.Settings; public class McpSettings { + public bool Enabled { get; set; } = true; public McpClientOptions McpClientOptions { get; set; } public List McpServerConfigs { get; set; } = new(); diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Image.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Image.cs index 2f70bd227..defd14592 100644 --- a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Image.cs +++ b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Image.cs @@ -57,7 +57,7 @@ public async Task GenerateImage(string text, InstructOptions? o { Id = innerAgentId, Instruction = instruction - }, new RoleDialogModel(AgentRole.User, text)); + }, new RoleDialogModel(AgentRole.User, instruction ?? text)); var hooks = _services.GetServices(); foreach (var hook in hooks) @@ -90,8 +90,6 @@ public async Task VaryImage(InstructFileModel image, InstructOp } var innerAgentId = options?.AgentId ?? Guid.Empty.ToString(); - var instruction = await GetAgentTemplate(innerAgentId, options?.TemplateName); - var completion = CompletionProvider.GetImageCompletion(_services, provider: options?.Provider ?? "openai", model: options?.Model ?? "dall-e-2"); var bytes = await DownloadFile(image); using var stream = new MemoryStream(); @@ -101,8 +99,7 @@ public async Task VaryImage(InstructFileModel image, InstructOp var fileName = $"{image.FileName ?? "image"}.{image.FileExtension ?? "png"}"; var message = await completion.GetImageVariation(new Agent() { - Id = innerAgentId, - Instruction = instruction + Id = innerAgentId }, new RoleDialogModel(AgentRole.User, string.Empty), stream, fileName); stream.Close(); @@ -120,9 +117,7 @@ await hook.OnResponseGenerated(new InstructResponseModel AgentId = innerAgentId, Provider = completion.Provider, Model = completion.Model, - TemplateName = options?.TemplateName, UserMessage = string.Empty, - SystemInstruction = instruction, CompletionText = message.Content }); } @@ -149,9 +144,8 @@ public async Task EditImage(string text, InstructFileModel imag var fileName = $"{image.FileName ?? "image"}.{image.FileExtension ?? "png"}"; var message = await completion.GetImageEdits(new Agent() { - Id = innerAgentId, - Instruction = instruction - }, new RoleDialogModel(AgentRole.User, text), stream, fileName); + Id = innerAgentId + }, new RoleDialogModel(AgentRole.User, instruction ?? text), stream, fileName); stream.Close(); @@ -205,9 +199,8 @@ public async Task EditImage(string text, InstructFileModel imag var maskName = $"{mask.FileName ?? "mask"}.{mask.FileExtension ?? "png"}"; var message = await completion.GetImageEdits(new Agent() { - Id = innerAgentId, - Instruction = instruction - }, new RoleDialogModel(AgentRole.User, text), imageStream, imageName, maskStream, maskName); + Id = innerAgentId + }, new RoleDialogModel(AgentRole.User, instruction ?? text), imageStream, imageName, maskStream, maskName); imageStream.Close(); maskStream.Close(); @@ -234,23 +227,4 @@ await hook.OnResponseGenerated(new InstructResponseModel return message; } - - #region Private methods - private async Task DownloadFile(InstructFileModel file) - { - var bytes = new byte[0]; - if (!string.IsNullOrEmpty(file.FileUrl)) - { - var http = _services.GetRequiredService(); - using var client = http.CreateClient(); - bytes = await client.GetByteArrayAsync(file.FileUrl); - } - else if (!string.IsNullOrEmpty(file.FileData)) - { - (_, bytes) = FileUtility.GetFileInfoFromData(file.FileData); - } - - return bytes; - } - #endregion } diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.SelectFile.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.SelectFile.cs index 0e049b206..c789e0696 100644 --- a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.SelectFile.cs +++ b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.SelectFile.cs @@ -93,10 +93,9 @@ private async Task> SelectFiles(IEnumerable x == providerName); - var model = llmProviderService.GetProviderModel(provider: provider, id: modelId); - var completion = CompletionProvider.GetChatCompletion(_services, provider: provider, model: model.Name); + var completion = CompletionProvider.GetChatCompletion(_services, provider: provider, model: model); var response = await completion.GetChatCompletions(agent, new List { message }); var content = response?.Content ?? string.Empty; diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.cs index b2da5f434..9ff3b46a7 100644 --- a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.cs +++ b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.cs @@ -19,6 +19,7 @@ public FileInstructService( _services = services; } + #region Private methods private void DeleteIfExistDirectory(string? dir, bool createNew = false) { if (_fileStorage.ExistDirectory(dir)) @@ -31,6 +32,23 @@ private void DeleteIfExistDirectory(string? dir, bool createNew = false) } } + private async Task DownloadFile(InstructFileModel file) + { + var bytes = new byte[0]; + if (!string.IsNullOrEmpty(file.FileUrl)) + { + var http = _services.GetRequiredService(); + using var client = http.CreateClient(); + bytes = await client.GetByteArrayAsync(file.FileUrl); + } + else if (!string.IsNullOrEmpty(file.FileData)) + { + (_, bytes) = FileUtility.GetFileInfoFromData(file.FileData); + } + + return bytes; + } + private async Task GetAgentTemplate(string agentId, string? templateName) { if (string.IsNullOrWhiteSpace(agentId) || string.IsNullOrWhiteSpace(templateName)) @@ -48,4 +66,5 @@ private void DeleteIfExistDirectory(string? dir, bool createNew = false) var instruction = agentService.RenderedTemplate(agent, templateName); return instruction; } + #endregion } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs index 55837f8d5..abf3c6e37 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs @@ -242,8 +242,7 @@ public async Task ImageVariation([FromBody] ImageVaria { Provider = input.Provider, Model = input.Model, - AgentId = input.AgentId, - TemplateName = input.TemplateName + AgentId = input.AgentId }); imageViewModel.Content = message.Content; imageViewModel.Images = message.GeneratedImages.Select(x => ImageViewModel.ToViewModel(x)).ToList(); @@ -262,7 +261,7 @@ public async Task ImageVariation([FromBody] ImageVaria [HttpPost("/instruct/image-variation/upload")] public async Task ImageVariation(IFormFile file, [FromForm] string? provider = null, [FromForm] string? model = null, [FromForm] List? states = null, - [FromForm] string? agentId = null, [FromForm] string? templateName = null) + [FromForm] string? agentId = null) { var state = _services.GetRequiredService(); states?.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External)); @@ -276,8 +275,7 @@ public async Task ImageVariation(IFormFile file, [From { Provider = provider, Model = model, - AgentId = agentId, - TemplateName = templateName + AgentId = agentId }); imageViewModel.Content = message.Content; diff --git a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.Edit.cs b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.Edit.cs index 47df077ef..71c0d6916 100644 --- a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.Edit.cs +++ b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.Edit.cs @@ -1,5 +1,4 @@ using OpenAI.Images; -using static System.Net.Mime.MediaTypeNames; namespace BotSharp.Plugin.OpenAI.Providers.Image; diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json index 60aca7d30..c5d82692d 100644 --- a/src/WebStarter/appsettings.json +++ b/src/WebStarter/appsettings.json @@ -172,7 +172,8 @@ } }, - "MCPSettings": { + "MCP": { + "Enabled": true, "McpClientOptions": { "ClientInfo": { "Name": "SimpleToolsBotsharp",