diff --git a/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/ExecuteTemplateArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/ExecuteTemplateArgs.cs new file mode 100644 index 00000000..e3d2405e --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/ExecuteTemplateArgs.cs @@ -0,0 +1,7 @@ +namespace BotSharp.Abstraction.Instructs.Models; + +public class ExecuteTemplateArgs +{ + [JsonPropertyName("template_name")] + public string? TemplateName { get; set; } +} diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj index 00e1f30a..ad6b4e19 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj +++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj @@ -90,6 +90,7 @@ + @@ -187,6 +188,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/src/Infrastructure/BotSharp.Core/Instructs/Functions/ExecuteTemplateFn.cs b/src/Infrastructure/BotSharp.Core/Instructs/Functions/ExecuteTemplateFn.cs new file mode 100644 index 00000000..b09019e3 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Instructs/Functions/ExecuteTemplateFn.cs @@ -0,0 +1,69 @@ +using BotSharp.Abstraction.Functions; +using BotSharp.Abstraction.Instructs.Models; + +namespace BotSharp.Core.Instructs.Functions; + +public class ExecuteTemplateFn : IFunctionCallback +{ + public string Name => "util-instruct-execute_template"; + + private readonly IServiceProvider _services; + private readonly ILogger _logger; + + public ExecuteTemplateFn( + IServiceProvider services, + ILogger logger) + { + _services = services; + _logger = logger; + } + + public async Task Execute(RoleDialogModel message) + { + var args = JsonSerializer.Deserialize(message.FunctionArgs); + if (string.IsNullOrEmpty(args.TemplateName)) + { + message.Content = $"Empty template name."; + return false; + } + + var agentService = _services.GetRequiredService(); + var agent = await agentService.GetAgent(message.CurrentAgentId); + var template = agent.Templates.FirstOrDefault(x => x.Name.IsEqualTo(args.TemplateName)); + + if (template == null) + { + message.Content = $"Cannot find template ({args.TemplateName}) in agent {agent.Name}"; + return false; + } + + var prompt = agentService.RenderedTemplate(agent, args.TemplateName); + var response = await GetAiResponse(agent, prompt); + message.Content = response; + return true; + } + + private async Task GetAiResponse(Agent agent, string text) + { + try + { + var completion = CompletionProvider.GetChatCompletion(_services, provider: agent.LlmConfig?.Provider, model: agent.LlmConfig?.Model); + var response = await completion.GetChatCompletions(new Agent() + { + Id = agent.Id + }, + new List + { + new(AgentRole.User, text) + }); + return response.Content; + } + catch (Exception ex) + { + var error = $"Error when getting agent {agent.Name} instruction response."; + _logger.LogWarning($"{error} {ex.Message}\r\n{ex.InnerException}"); + return error; + } + + } +} diff --git a/src/Infrastructure/BotSharp.Core/Instructs/Hooks/InstructUtilityHook.cs b/src/Infrastructure/BotSharp.Core/Instructs/Hooks/InstructUtilityHook.cs new file mode 100644 index 00000000..e0c6d686 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Instructs/Hooks/InstructUtilityHook.cs @@ -0,0 +1,17 @@ +namespace BotSharp.Core.Instructs.Hooks; + +public class InstructUtilityHook : IAgentUtilityHook +{ + private static string PREFIX = "util-instruct-"; + private static string EXECUTE_TEMPLATE = $"{PREFIX}execute_template"; + + public void AddUtilities(List utilities) + { + utilities.Add(new AgentUtility + { + Name = "instruct.template", + Functions = [new($"{EXECUTE_TEMPLATE}")], + Templates = [new($"{EXECUTE_TEMPLATE}.fn")] + }); + } +} diff --git a/src/Infrastructure/BotSharp.Core/Instructs/InsturctionPlugin.cs b/src/Infrastructure/BotSharp.Core/Instructs/InsturctionPlugin.cs index c44cb874..7bde20e8 100644 --- a/src/Infrastructure/BotSharp.Core/Instructs/InsturctionPlugin.cs +++ b/src/Infrastructure/BotSharp.Core/Instructs/InsturctionPlugin.cs @@ -1,6 +1,7 @@ using BotSharp.Abstraction.Instructs.Settings; using BotSharp.Abstraction.Plugins.Models; using BotSharp.Abstraction.Settings; +using BotSharp.Core.Instructs.Hooks; using Microsoft.Extensions.Configuration; namespace BotSharp.Core.Instructs; @@ -18,6 +19,8 @@ public class InsturctionPlugin : IBotSharpPlugin var settingService = provider.GetRequiredService(); return settingService.Bind("Instruction"); }); + + services.AddScoped(); } public bool AttachMenu(List menu) diff --git a/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingUtilityHook.cs b/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingUtilityHook.cs index e6fedc05..de7a556b 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingUtilityHook.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingUtilityHook.cs @@ -8,13 +8,11 @@ public class RoutingUtilityHook : IAgentUtilityHook public void AddUtilities(List utilities) { - var utility = new AgentUtility + utilities.Add(new AgentUtility { Name = "routing.tools", Functions = [new($"{REDIRECT_TO_AGENT}"), new($"{FALLBACK_TO_ROUTER}")], Templates = [new($"{REDIRECT_TO_AGENT}.fn"), new($"{FALLBACK_TO_ROUTER}.fn")] - }; - - utilities.Add(utility); + }); } } diff --git a/src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-instruct-execute_template.json b/src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-instruct-execute_template.json new file mode 100644 index 00000000..52780e61 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-instruct-execute_template.json @@ -0,0 +1,14 @@ +{ + "name": "util-instruct-execute_template", + "description": "Select a specific template that can handle the user's request.", + "parameters": { + "type": "object", + "properties": { + "template_name": { + "type": "string", + "description": "The template name that is selected for handling the request." + } + }, + "required": [ "template_name" ] + } +} \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/util-instruct-execute_template.fn.liquid b/src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/util-instruct-execute_template.fn.liquid new file mode 100644 index 00000000..78291d3b --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/util-instruct-execute_template.fn.liquid @@ -0,0 +1,3 @@ +please call function util-routing-execute_template if user wants to use a template to fulfill a specific task. +Please ensure the template is executed only once. +Please output the template response directly without changing anthything. \ No newline at end of file