From 2e0069d4e50eb209608dc6698a1bf8f48ed1fed9 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Tue, 30 Sep 2025 15:03:06 -0500 Subject: [PATCH] init code template in instruct service --- .../CodeInterpreter/ICodeInterpretService.cs | 2 +- .../Instructs/IInstructService.cs | 13 ++-- .../Instructs/Models/CodeInstructOptions.cs | 7 ++ .../Instructs/Models/InstructResult.cs | 3 +- .../BotSharp.Abstraction/Models/KeyValue.cs | 11 +++ .../Services/InstructService.Execute.cs | 67 +++++++++++++------ .../Controllers/InstructModeController.cs | 5 +- .../Instructs/Request/InstructMessageModel.cs | 3 + .../Services/PyInterpretService.cs | 15 +++-- 9 files changed, 91 insertions(+), 35 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Abstraction/Instructs/Models/CodeInstructOptions.cs diff --git a/src/Infrastructure/BotSharp.Abstraction/CodeInterpreter/ICodeInterpretService.cs b/src/Infrastructure/BotSharp.Abstraction/CodeInterpreter/ICodeInterpretService.cs index 05afe3c1..306ab242 100644 --- a/src/Infrastructure/BotSharp.Abstraction/CodeInterpreter/ICodeInterpretService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/CodeInterpreter/ICodeInterpretService.cs @@ -6,5 +6,5 @@ public interface ICodeInterpretService { string Provider { get; } - Task RunCode(string code, List? arguments = null, CodeInterpretOptions? options = null); + Task RunCode(string code, IEnumerable? arguments = null, CodeInterpretOptions? options = null); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructService.cs b/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructService.cs index 7dce2423..00d7534a 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructService.cs @@ -7,13 +7,16 @@ public interface IInstructService /// /// Execute completion by using specified instruction or template /// - /// Agent (static agent) - /// Additional message provided by user - /// Template name - /// System prompt + /// + /// + /// + /// + /// + /// /// Task Execute(string agentId, RoleDialogModel message, - string? templateName = null, string? instruction = null, IEnumerable? files = null); + string? instruction = null, string? llmTemplateName = null, + IEnumerable? files = null, CodeInstructOptions? codeOptions = null); /// /// A generic way to execute completion by using specified instruction or template diff --git a/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/CodeInstructOptions.cs b/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/CodeInstructOptions.cs new file mode 100644 index 00000000..9b9265f4 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/CodeInstructOptions.cs @@ -0,0 +1,7 @@ +namespace BotSharp.Abstraction.Instructs.Models; + +public class CodeInstructOptions +{ + public string? CodeTemplateName { get; set; } + public string? CodeInterpretProvider { get; set; } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/InstructResult.cs b/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/InstructResult.cs index fe236863..efaf4ffd 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/InstructResult.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/InstructResult.cs @@ -6,7 +6,8 @@ public class InstructResult : ITrackableMessage public string MessageId { get; set; } public string Text { get; set; } = string.Empty; public object? Data { get; set; } + [JsonPropertyName("template")] - public string? Template{ get; set; } + public string? Template { get; set; } public Dictionary? States { get; set; } = new(); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Models/KeyValue.cs b/src/Infrastructure/BotSharp.Abstraction/Models/KeyValue.cs index 3cb9c73f..8bf0e189 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Models/KeyValue.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Models/KeyValue.cs @@ -8,6 +8,17 @@ public class KeyValue [JsonPropertyName("value")] public string? Value { get; set; } + public KeyValue() + { + + } + + public KeyValue(string key, string? value) + { + Key = key; + Value = value; + } + public override string ToString() { return $"Key: {Key}, Value: {Value}"; diff --git a/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs b/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs index 773392f1..e09caf01 100644 --- a/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs +++ b/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs @@ -1,36 +1,67 @@ +using BotSharp.Abstraction.CodeInterpreter; using BotSharp.Abstraction.Instructs; using BotSharp.Abstraction.Instructs.Models; using BotSharp.Abstraction.MLTasks; +using BotSharp.Abstraction.Models; namespace BotSharp.Core.Instructs; public partial class InstructService { - public async Task Execute(string agentId, RoleDialogModel message, - string? templateName = null, string? instruction = null, IEnumerable? files = null) + public async Task Execute( + string agentId, + RoleDialogModel message, + string? instruction = null, + string? llmTemplateName = null, + IEnumerable? files = null, + CodeInstructOptions? codeOptions = null) { var agentService = _services.GetRequiredService(); Agent agent = await agentService.LoadAgent(agentId); + var response = new InstructResult + { + MessageId = message.MessageId, + Template = codeOptions?.CodeTemplateName ?? llmTemplateName + }; + + if (agent == null) { - return new InstructResult - { - MessageId = message.MessageId, - Text = $"Agent (id: {agentId}) does not exist!" - }; + response.Text = $"Agent (id: {agentId}) does not exist!"; + return response; } if (agent.Disabled) { var content = $"This agent ({agent.Name}) is disabled, please install the corresponding plugin ({agent.Plugin.Name}) to activate this agent."; - return new InstructResult - { - MessageId = message.MessageId, - Text = content - }; + response.Text = content; + return response; } + // Run code template + if (!string.IsNullOrWhiteSpace(codeOptions?.CodeTemplateName)) + { + var codeInterpreter = _services.GetServices() + .FirstOrDefault(x => x.Provider.IsEqualTo(codeOptions?.CodeInterpretProvider.IfNullOrEmptyAs("python-interpreter"))); + + if (codeInterpreter == null) + { + var error = "No code interpreter found."; + _logger.LogError(error); + response.Text = error; + } + else + { + var state = _services.GetRequiredService(); + var arguments = state.GetStates().Select(x => new KeyValue(x.Key, x.Value)); + var result = await codeInterpreter.RunCode("", arguments); + response.Text = result?.Result?.ToString(); + } + return response; + } + + // Trigger before completion hooks var hooks = _services.GetHooks(agentId); foreach (var hook in hooks) @@ -52,19 +83,13 @@ public partial class InstructService var model = string.Empty; // Render prompt - var prompt = string.IsNullOrEmpty(templateName) ? + var prompt = string.IsNullOrEmpty(llmTemplateName) ? agentService.RenderInstruction(agent) : - agentService.RenderTemplate(agent, templateName); + agentService.RenderTemplate(agent, llmTemplateName); var completer = CompletionProvider.GetCompletion(_services, agentConfig: agent.LlmConfig); - var response = new InstructResult - { - MessageId = message.MessageId, - Template = templateName, - }; - if (completer is ITextCompletion textCompleter) { instruction = null; @@ -111,7 +136,7 @@ public partial class InstructService AgentId = agentId, Provider = provider, Model = model, - TemplateName = templateName, + TemplateName = llmTemplateName, UserMessage = prompt, SystemInstruction = instruction, CompletionText = response.Text diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs index 852d780a..ad4904c0 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs @@ -36,9 +36,10 @@ public class InstructModeController : ControllerBase var instructor = _services.GetRequiredService(); var result = await instructor.Execute(agentId, new RoleDialogModel(AgentRole.User, input.Text), - templateName: input.Template, instruction: input.Instruction, - files: input.Files); + llmTemplateName: input.Template, + files: input.Files, + codeOptions: input.CodeOptions); result.States = state.GetStates(); diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/Request/InstructMessageModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/Request/InstructMessageModel.cs index aec81ffb..05c151be 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/Request/InstructMessageModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/Request/InstructMessageModel.cs @@ -1,3 +1,5 @@ +using BotSharp.Abstraction.Instructs.Models; + namespace BotSharp.OpenAPI.ViewModels.Instructs; public class InstructMessageModel : IncomingMessageModel @@ -9,6 +11,7 @@ public class InstructMessageModel : IncomingMessageModel public override string Channel { get; set; } = ConversationChannel.OpenAPI; public string? Template { get; set; } public List Files { get; set; } = []; + public CodeInstructOptions? CodeOptions { get; set; } } diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Services/PyInterpretService.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Services/PyInterpretService.cs index 5fe00abf..a88e3a7c 100644 --- a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Services/PyInterpretService.cs +++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Services/PyInterpretService.cs @@ -20,7 +20,8 @@ public class PyInterpretService : ICodeInterpretService public string Provider => "python-interpreter"; - public async Task RunCode(string code, List? arguments = null, CodeInterpretOptions? options = null) + public async Task RunCode(string code, + IEnumerable? arguments = null, CodeInterpretOptions? options = null) { try { @@ -45,14 +46,18 @@ public class PyInterpretService : ICodeInterpretService // Set arguments if (!arguments.IsNullOrEmpty()) { - sys.argv = new PyList(); - sys.argv.Append("code.py"); + var list = new PyList(); + list.Append(new PyString("code.py")); foreach (var arg in arguments) { - sys.argv.Append($"--{arg.Key}"); - sys.argv.Append($"{arg.Value}"); + if (!string.IsNullOrWhiteSpace(arg.Key) && !string.IsNullOrWhiteSpace(arg.Value)) + { + list.Append(new PyString($"--{arg.Key}")); + list.Append(new PyString($"{arg.Value}")); + } } + sys.argv = list; } // Execute Python script