Merge pull request #979 from iceljc/master

fix file selection
This commit is contained in:
iceljc 2025-04-01 10:41:41 -05:00 committed by GitHub
commit da14d000fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 87 additions and 53 deletions

View file

@ -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()

View file

@ -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

View file

@ -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);

View file

@ -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)

View file

@ -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()

View 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;
}
}

View file

@ -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();

View file

@ -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
} }

View file

@ -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;

View file

@ -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
} }

View file

@ -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;

View file

@ -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;

View file

@ -172,7 +172,8 @@
} }
}, },
"MCPSettings": { "MCP": {
"Enabled": true,
"McpClientOptions": { "McpClientOptions": {
"ClientInfo": { "ClientInfo": {
"Name": "SimpleToolsBotsharp", "Name": "SimpleToolsBotsharp",