commit
da14d000fa
|
|
@ -2,9 +2,16 @@ namespace BotSharp.Abstraction.Agents.Models;
|
||||||
|
|
||||||
public class McpTool
|
public class McpTool
|
||||||
{
|
{
|
||||||
|
[JsonPropertyName("name")]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("server_id")]
|
||||||
public string ServerId { get; set; }
|
public string ServerId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("disabled")]
|
||||||
public bool Disabled { get; set; }
|
public bool Disabled { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("functions")]
|
||||||
public IEnumerable<McpFunction> Functions { get; set; } = [];
|
public IEnumerable<McpFunction> Functions { get; set; } = [];
|
||||||
|
|
||||||
public McpTool()
|
public McpTool()
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ public class SelectFileOptions
|
||||||
public string? Provider { get; set; }
|
public string? Provider { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Llm model id
|
/// Llm model
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? ModelId { get; set; }
|
public string? Model { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Agent id
|
/// Agent id
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,9 @@ public static class BotSharpMcpExtensions
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static IServiceCollection AddBotSharpMCP(this IServiceCollection services, IConfiguration config)
|
public static IServiceCollection AddBotSharpMCP(this IServiceCollection services, IConfiguration config)
|
||||||
{
|
{
|
||||||
var settings = config.GetSection("MCPSettings").Get<McpSettings>();
|
var settings = config.GetSection("MCP").Get<McpSettings>();
|
||||||
services.AddScoped<McpSettings>(provider => { return settings; });
|
services.AddScoped(provider => { return settings; });
|
||||||
if (settings != null && !settings.McpServerConfigs.IsNullOrEmpty())
|
if (settings != null && settings.Enabled && !settings.McpServerConfigs.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
var clientManager = new McpClientManager(settings);
|
var clientManager = new McpClientManager(settings);
|
||||||
services.AddSingleton(clientManager);
|
services.AddSingleton(clientManager);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using BotSharp.Core.MCP.Helpers;
|
using BotSharp.Core.MCP.Helpers;
|
||||||
using BotSharp.Core.MCP.Managers;
|
using BotSharp.Core.MCP.Managers;
|
||||||
|
using BotSharp.Core.MCP.Settings;
|
||||||
using ModelContextProtocol.Client;
|
using ModelContextProtocol.Client;
|
||||||
|
|
||||||
namespace BotSharp.Core.MCP.Hooks;
|
namespace BotSharp.Core.MCP.Hooks;
|
||||||
|
|
@ -39,6 +40,13 @@ public class McpToolAgentHook : AgentHookBase
|
||||||
private async Task<IEnumerable<FunctionDef>> GetMcpContent(Agent agent)
|
private async Task<IEnumerable<FunctionDef>> GetMcpContent(Agent agent)
|
||||||
{
|
{
|
||||||
var functionDefs = new List<FunctionDef>();
|
var functionDefs = new List<FunctionDef>();
|
||||||
|
|
||||||
|
var settings = _services.GetRequiredService<McpSettings>();
|
||||||
|
if (settings?.Enabled != true)
|
||||||
|
{
|
||||||
|
return functionDefs;
|
||||||
|
}
|
||||||
|
|
||||||
var mcpClientManager = _services.GetRequiredService<McpClientManager>();
|
var mcpClientManager = _services.GetRequiredService<McpClientManager>();
|
||||||
var mcps = agent.McpTools.Where(x => !x.Disabled);
|
var mcps = agent.McpTools.Where(x => !x.Disabled);
|
||||||
foreach (var item in mcps)
|
foreach (var item in mcps)
|
||||||
|
|
|
||||||
|
|
@ -5,19 +5,18 @@ namespace BotSharp.Core.MCP.Managers;
|
||||||
|
|
||||||
public class McpClientManager : IDisposable
|
public class McpClientManager : IDisposable
|
||||||
{
|
{
|
||||||
|
private readonly McpSettings _mcpSettings;
|
||||||
|
|
||||||
private readonly McpSettings mcpSettings;
|
public McpClientManager(McpSettings mcpSettings)
|
||||||
|
|
||||||
public McpClientManager(McpSettings settings)
|
|
||||||
{
|
{
|
||||||
mcpSettings = settings;
|
_mcpSettings = mcpSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IMcpClient> GetMcpClientAsync(string serverId)
|
public async Task<IMcpClient> GetMcpClientAsync(string serverId)
|
||||||
{
|
{
|
||||||
return await McpClientFactory.CreateAsync(
|
return await McpClientFactory.CreateAsync(
|
||||||
mcpSettings.McpServerConfigs.Where(x=> x.Name == serverId).First(),
|
_mcpSettings.McpServerConfigs.Where(x=> x.Name == serverId).First(),
|
||||||
mcpSettings.McpClientOptions);
|
_mcpSettings.McpClientOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|
|
||||||
29
src/Infrastructure/BotSharp.Core.MCP/McpPlugin.cs
Normal file
29
src/Infrastructure/BotSharp.Core.MCP/McpPlugin.cs
Normal file
|
|
@ -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<PluginMenuDef> menu)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ namespace BotSharp.Core.MCP.Settings;
|
||||||
|
|
||||||
public class McpSettings
|
public class McpSettings
|
||||||
{
|
{
|
||||||
|
public bool Enabled { get; set; } = true;
|
||||||
public McpClientOptions McpClientOptions { get; set; }
|
public McpClientOptions McpClientOptions { get; set; }
|
||||||
public List<McpServerConfig> McpServerConfigs { get; set; } = new();
|
public List<McpServerConfig> McpServerConfigs { get; set; } = new();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ public partial class FileInstructService
|
||||||
{
|
{
|
||||||
Id = innerAgentId,
|
Id = innerAgentId,
|
||||||
Instruction = instruction
|
Instruction = instruction
|
||||||
}, new RoleDialogModel(AgentRole.User, text));
|
}, new RoleDialogModel(AgentRole.User, instruction ?? text));
|
||||||
|
|
||||||
var hooks = _services.GetServices<IInstructHook>();
|
var hooks = _services.GetServices<IInstructHook>();
|
||||||
foreach (var hook in hooks)
|
foreach (var hook in hooks)
|
||||||
|
|
@ -90,8 +90,6 @@ public partial class FileInstructService
|
||||||
}
|
}
|
||||||
|
|
||||||
var innerAgentId = options?.AgentId ?? Guid.Empty.ToString();
|
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 completion = CompletionProvider.GetImageCompletion(_services, provider: options?.Provider ?? "openai", model: options?.Model ?? "dall-e-2");
|
||||||
var bytes = await DownloadFile(image);
|
var bytes = await DownloadFile(image);
|
||||||
using var stream = new MemoryStream();
|
using var stream = new MemoryStream();
|
||||||
|
|
@ -101,8 +99,7 @@ public partial class FileInstructService
|
||||||
var fileName = $"{image.FileName ?? "image"}.{image.FileExtension ?? "png"}";
|
var fileName = $"{image.FileName ?? "image"}.{image.FileExtension ?? "png"}";
|
||||||
var message = await completion.GetImageVariation(new Agent()
|
var message = await completion.GetImageVariation(new Agent()
|
||||||
{
|
{
|
||||||
Id = innerAgentId,
|
Id = innerAgentId
|
||||||
Instruction = instruction
|
|
||||||
}, new RoleDialogModel(AgentRole.User, string.Empty), stream, fileName);
|
}, new RoleDialogModel(AgentRole.User, string.Empty), stream, fileName);
|
||||||
|
|
||||||
stream.Close();
|
stream.Close();
|
||||||
|
|
@ -120,9 +117,7 @@ public partial class FileInstructService
|
||||||
AgentId = innerAgentId,
|
AgentId = innerAgentId,
|
||||||
Provider = completion.Provider,
|
Provider = completion.Provider,
|
||||||
Model = completion.Model,
|
Model = completion.Model,
|
||||||
TemplateName = options?.TemplateName,
|
|
||||||
UserMessage = string.Empty,
|
UserMessage = string.Empty,
|
||||||
SystemInstruction = instruction,
|
|
||||||
CompletionText = message.Content
|
CompletionText = message.Content
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -149,9 +144,8 @@ public partial class FileInstructService
|
||||||
var fileName = $"{image.FileName ?? "image"}.{image.FileExtension ?? "png"}";
|
var fileName = $"{image.FileName ?? "image"}.{image.FileExtension ?? "png"}";
|
||||||
var message = await completion.GetImageEdits(new Agent()
|
var message = await completion.GetImageEdits(new Agent()
|
||||||
{
|
{
|
||||||
Id = innerAgentId,
|
Id = innerAgentId
|
||||||
Instruction = instruction
|
}, new RoleDialogModel(AgentRole.User, instruction ?? text), stream, fileName);
|
||||||
}, new RoleDialogModel(AgentRole.User, text), stream, fileName);
|
|
||||||
|
|
||||||
stream.Close();
|
stream.Close();
|
||||||
|
|
||||||
|
|
@ -205,9 +199,8 @@ public partial class FileInstructService
|
||||||
var maskName = $"{mask.FileName ?? "mask"}.{mask.FileExtension ?? "png"}";
|
var maskName = $"{mask.FileName ?? "mask"}.{mask.FileExtension ?? "png"}";
|
||||||
var message = await completion.GetImageEdits(new Agent()
|
var message = await completion.GetImageEdits(new Agent()
|
||||||
{
|
{
|
||||||
Id = innerAgentId,
|
Id = innerAgentId
|
||||||
Instruction = instruction
|
}, new RoleDialogModel(AgentRole.User, instruction ?? text), imageStream, imageName, maskStream, maskName);
|
||||||
}, new RoleDialogModel(AgentRole.User, text), imageStream, imageName, maskStream, maskName);
|
|
||||||
|
|
||||||
imageStream.Close();
|
imageStream.Close();
|
||||||
maskStream.Close();
|
maskStream.Close();
|
||||||
|
|
@ -234,23 +227,4 @@ public partial class FileInstructService
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Private methods
|
|
||||||
private async Task<byte[]> DownloadFile(InstructFileModel file)
|
|
||||||
{
|
|
||||||
var bytes = new byte[0];
|
|
||||||
if (!string.IsNullOrEmpty(file.FileUrl))
|
|
||||||
{
|
|
||||||
var http = _services.GetRequiredService<IHttpClientFactory>();
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,10 +93,9 @@ public partial class FileInstructService
|
||||||
}
|
}
|
||||||
|
|
||||||
var providerName = options.Provider ?? "openai";
|
var providerName = options.Provider ?? "openai";
|
||||||
var modelId = options?.ModelId ?? "gpt-4o";
|
var model = options?.Model ?? "gpt-4o-mini";
|
||||||
var provider = llmProviderService.GetProviders().FirstOrDefault(x => x == providerName);
|
var provider = llmProviderService.GetProviders().FirstOrDefault(x => x == providerName);
|
||||||
var model = llmProviderService.GetProviderModel(provider: provider, id: modelId);
|
var completion = CompletionProvider.GetChatCompletion(_services, provider: provider, model: model);
|
||||||
var completion = CompletionProvider.GetChatCompletion(_services, provider: provider, model: model.Name);
|
|
||||||
|
|
||||||
var response = await completion.GetChatCompletions(agent, new List<RoleDialogModel> { message });
|
var response = await completion.GetChatCompletions(agent, new List<RoleDialogModel> { message });
|
||||||
var content = response?.Content ?? string.Empty;
|
var content = response?.Content ?? string.Empty;
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ public partial class FileInstructService : IFileInstructService
|
||||||
_services = services;
|
_services = services;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Private methods
|
||||||
private void DeleteIfExistDirectory(string? dir, bool createNew = false)
|
private void DeleteIfExistDirectory(string? dir, bool createNew = false)
|
||||||
{
|
{
|
||||||
if (_fileStorage.ExistDirectory(dir))
|
if (_fileStorage.ExistDirectory(dir))
|
||||||
|
|
@ -31,6 +32,23 @@ public partial class FileInstructService : IFileInstructService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<byte[]> DownloadFile(InstructFileModel file)
|
||||||
|
{
|
||||||
|
var bytes = new byte[0];
|
||||||
|
if (!string.IsNullOrEmpty(file.FileUrl))
|
||||||
|
{
|
||||||
|
var http = _services.GetRequiredService<IHttpClientFactory>();
|
||||||
|
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<string?> GetAgentTemplate(string agentId, string? templateName)
|
private async Task<string?> GetAgentTemplate(string agentId, string? templateName)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(agentId) || string.IsNullOrWhiteSpace(templateName))
|
if (string.IsNullOrWhiteSpace(agentId) || string.IsNullOrWhiteSpace(templateName))
|
||||||
|
|
@ -48,4 +66,5 @@ public partial class FileInstructService : IFileInstructService
|
||||||
var instruction = agentService.RenderedTemplate(agent, templateName);
|
var instruction = agentService.RenderedTemplate(agent, templateName);
|
||||||
return instruction;
|
return instruction;
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -242,8 +242,7 @@ public class InstructModeController : ControllerBase
|
||||||
{
|
{
|
||||||
Provider = input.Provider,
|
Provider = input.Provider,
|
||||||
Model = input.Model,
|
Model = input.Model,
|
||||||
AgentId = input.AgentId,
|
AgentId = input.AgentId
|
||||||
TemplateName = input.TemplateName
|
|
||||||
});
|
});
|
||||||
imageViewModel.Content = message.Content;
|
imageViewModel.Content = message.Content;
|
||||||
imageViewModel.Images = message.GeneratedImages.Select(x => ImageViewModel.ToViewModel(x)).ToList();
|
imageViewModel.Images = message.GeneratedImages.Select(x => ImageViewModel.ToViewModel(x)).ToList();
|
||||||
|
|
@ -262,7 +261,7 @@ public class InstructModeController : ControllerBase
|
||||||
[HttpPost("/instruct/image-variation/upload")]
|
[HttpPost("/instruct/image-variation/upload")]
|
||||||
public async Task<ImageGenerationViewModel> ImageVariation(IFormFile file, [FromForm] string? provider = null,
|
public async Task<ImageGenerationViewModel> ImageVariation(IFormFile file, [FromForm] string? provider = null,
|
||||||
[FromForm] string? model = null, [FromForm] List<MessageState>? states = null,
|
[FromForm] string? model = null, [FromForm] List<MessageState>? states = null,
|
||||||
[FromForm] string? agentId = null, [FromForm] string? templateName = null)
|
[FromForm] string? agentId = null)
|
||||||
{
|
{
|
||||||
var state = _services.GetRequiredService<IConversationStateService>();
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
states?.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
|
states?.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
|
||||||
|
|
@ -276,8 +275,7 @@ public class InstructModeController : ControllerBase
|
||||||
{
|
{
|
||||||
Provider = provider,
|
Provider = provider,
|
||||||
Model = model,
|
Model = model,
|
||||||
AgentId = agentId,
|
AgentId = agentId
|
||||||
TemplateName = templateName
|
|
||||||
});
|
});
|
||||||
|
|
||||||
imageViewModel.Content = message.Content;
|
imageViewModel.Content = message.Content;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using OpenAI.Images;
|
using OpenAI.Images;
|
||||||
using static System.Net.Mime.MediaTypeNames;
|
|
||||||
|
|
||||||
namespace BotSharp.Plugin.OpenAI.Providers.Image;
|
namespace BotSharp.Plugin.OpenAI.Providers.Image;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"MCPSettings": {
|
"MCP": {
|
||||||
|
"Enabled": true,
|
||||||
"McpClientOptions": {
|
"McpClientOptions": {
|
||||||
"ClientInfo": {
|
"ClientInfo": {
|
||||||
"Name": "SimpleToolsBotsharp",
|
"Name": "SimpleToolsBotsharp",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue