diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Models/FileLlmProcessOptions.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Models/FileLlmProcessOptions.cs new file mode 100644 index 00000000..343fd1f4 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Files/Models/FileLlmProcessOptions.cs @@ -0,0 +1,34 @@ +namespace BotSharp.Abstraction.Files.Models; + +public class FileLlmProcessOptions +{ + /// + /// Llm provider + /// + public string? LlmProvider { get; set; } + + /// + /// llm model + /// + public string? LlModel { get; set; } + + /// + /// Reasoning effort level + /// + public string? ReasoningEfforLevel { get; set; } + + /// + /// Instruction + /// + public string? Instruction { get; set; } + + /// + /// Template name in Agent + /// + public string? TemplateName { get; set; } + + /// + /// Data that is used to render instruction + /// + public Dictionary? Data { get; set; } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Proccessors/IFileLlmProcessor.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Proccessors/IFileLlmProcessor.cs new file mode 100644 index 00000000..f2102721 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Files/Proccessors/IFileLlmProcessor.cs @@ -0,0 +1,9 @@ +namespace BotSharp.Abstraction.Files.Proccessors; + +public interface IFileLlmProcessor +{ + public string Provider { get; } + + Task GetFileLlmInferenceAsync(Agent agent, string text, IEnumerable files, FileLlmProcessOptions? options = null) + => throw new NotImplementedException(); +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructService.cs b/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructService.cs index 3fe1c03f..30fc88ad 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructService.cs @@ -13,10 +13,13 @@ public interface IInstructService /// /// /// + /// /// Task Execute(string agentId, RoleDialogModel message, string? instruction = null, string? templateName = null, - IEnumerable? files = null, CodeInstructOptions? codeOptions = null); + IEnumerable? files = null, + CodeInstructOptions? codeOptions = null, + FileInstructOptions? fileOptions = null); /// /// A generic way to execute completion by using specified instruction or template diff --git a/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/FileInstructOptions.cs b/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/FileInstructOptions.cs new file mode 100644 index 00000000..a51db882 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/FileInstructOptions.cs @@ -0,0 +1,6 @@ +namespace BotSharp.Abstraction.Instructs.Models; + +public class FileInstructOptions +{ + public string? FileLlmProcessorProvider { get; set; } +} diff --git a/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs b/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs index e03e6352..cceb7bba 100644 --- a/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs +++ b/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.CodeInterpreter; +using BotSharp.Abstraction.Files.Proccessors; using BotSharp.Abstraction.Instructs; using BotSharp.Abstraction.Instructs.Models; using BotSharp.Abstraction.MLTasks; @@ -14,9 +15,11 @@ public partial class InstructService string? instruction = null, string? templateName = null, IEnumerable? files = null, - CodeInstructOptions? codeOptions = null) + CodeInstructOptions? codeOptions = null, + FileInstructOptions? fileOptions = null) { var agentService = _services.GetRequiredService(); + var state = _services.GetRequiredService(); Agent agent = await agentService.LoadAgent(agentId); var response = new InstructResult @@ -68,6 +71,7 @@ public partial class InstructService var provider = string.Empty; var model = string.Empty; + var result = string.Empty; // Render prompt var prompt = string.IsNullOrEmpty(templateName) ? @@ -83,13 +87,14 @@ public partial class InstructService provider = textCompleter.Provider; model = textCompleter.Model; - var result = await textCompleter.GetCompletion(prompt, agentId, message.MessageId); + result = await GetTextCompletion(textCompleter, agent, prompt, message.MessageId); response.Text = result; } else if (completer is IChatCompletion chatCompleter) { provider = chatCompleter.Provider; model = chatCompleter.Model; + if (instruction == "#TEMPLATE#") { @@ -97,21 +102,30 @@ public partial class InstructService prompt = message.Content; } - var result = await chatCompleter.GetChatCompletions(new Agent + IFileLlmProcessor? fileProcessor = null; + if (!files.IsNullOrEmpty() && !string.IsNullOrEmpty(fileOptions?.FileLlmProcessorProvider)) { - Id = agentId, - Name = agent.Name, - Instruction = instruction - }, new List + fileProcessor = _services.GetServices() + .FirstOrDefault(x => x.Provider.IsEqualTo(fileOptions?.FileLlmProcessorProvider)); + } + + if (fileProcessor != null) { - new RoleDialogModel(AgentRole.User, prompt) + var inference = await fileProcessor.GetFileLlmInferenceAsync(agent, prompt, files, new FileLlmProcessOptions { - CurrentAgentId = agentId, - MessageId = message.MessageId, - Files = files?.Select(x => new BotSharpFile { FileUrl = x.FileUrl, FileData = x.FileData, ContentType = x.ContentType }).ToList() ?? [] - } - }); - response.Text = result.Content; + LlmProvider = provider, + LlModel = model, + Instruction = instruction, + TemplateName = templateName, + Data = state.GetStates().ToDictionary(x => x.Key, x => (object)x.Value) + }); + result = inference?.Content ?? string.Empty; + } + else + { + result = await GetChatCompletion(chatCompleter, agent, instruction, prompt, message.MessageId, files); + } + response.Text = result; } // After completion hooks @@ -141,7 +155,11 @@ public partial class InstructService /// /// /// - private async Task GetCodeResponse(Agent agent, RoleDialogModel message, string templateName, CodeInstructOptions? codeOptions) + private async Task GetCodeResponse( + Agent agent, + RoleDialogModel message, + string templateName, + CodeInstructOptions? codeOptions) { InstructResult? response = null; @@ -261,4 +279,40 @@ public partial class InstructService return response; } + + private async Task GetTextCompletion( + ITextCompletion textCompleter, + Agent agent, + string text, + string messageId) + { + var result = await textCompleter.GetCompletion(text, agent.Id, messageId); + return result; + } + + private async Task GetChatCompletion( + IChatCompletion chatCompleter, + Agent agent, + string instruction, + string text, + string messageId, + IEnumerable? files = null) + { + var result = await chatCompleter.GetChatCompletions(new Agent + { + Id = agent.Id, + Name = agent.Name, + Instruction = instruction + }, new List + { + new RoleDialogModel(AgentRole.User, text) + { + CurrentAgentId = agent.Id, + MessageId = messageId, + Files = files?.Select(x => new BotSharpFile { FileUrl = x.FileUrl, FileData = x.FileData, ContentType = x.ContentType }).ToList() ?? [] + } + }); + + return result.Content; + } } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs index eab8637c..4b656db7 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs @@ -39,7 +39,8 @@ public class InstructModeController : ControllerBase instruction: input.Instruction, templateName: input.Template, files: input.Files, - codeOptions: input.CodeOptions); + codeOptions: input.CodeOptions, + fileOptions: input.FileOptions); result.States = state.GetStates(); return result; diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/Request/InstructMessageModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/Request/InstructMessageModel.cs index 05c151be..0091f02a 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/Request/InstructMessageModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/Request/InstructMessageModel.cs @@ -12,6 +12,7 @@ public class InstructMessageModel : IncomingMessageModel public string? Template { get; set; } public List Files { get; set; } = []; public CodeInstructOptions? CodeOptions { get; set; } + public FileInstructOptions? FileOptions { get; set; } }