From e529b36fabce546d16de4871107133060786b0b7 Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Mon, 29 Sep 2025 01:20:25 -0500 Subject: [PATCH] init --- .../BotSharp.Plugin.PythonInterpreter.csproj | 2 +- .../Functions/PyInterpretationFn.cs | 112 +++++++++++++++++- .../InterpreterPlugin.cs | 7 ++ .../LlmContext/LlmContextIn.cs | 9 ++ .../LlmContext/LlmContextOut.cs | 9 ++ .../Using.cs | 7 ++ .../util-code-python_interpreter.json | 15 +-- .../util-code-python_interpreter.fn.liquid | 2 +- 8 files changed, 146 insertions(+), 17 deletions(-) create mode 100644 src/Plugins/BotSharp.Plugin.PythonInterpreter/LlmContext/LlmContextIn.cs create mode 100644 src/Plugins/BotSharp.Plugin.PythonInterpreter/LlmContext/LlmContextOut.cs diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/BotSharp.Plugin.PythonInterpreter.csproj b/src/Plugins/BotSharp.Plugin.PythonInterpreter/BotSharp.Plugin.PythonInterpreter.csproj index ab15acf7..db85df01 100644 --- a/src/Plugins/BotSharp.Plugin.PythonInterpreter/BotSharp.Plugin.PythonInterpreter.csproj +++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/BotSharp.Plugin.PythonInterpreter.csproj @@ -33,7 +33,7 @@ - + diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Functions/PyInterpretationFn.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Functions/PyInterpretationFn.cs index 818340b9..7706f984 100644 --- a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Functions/PyInterpretationFn.cs +++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Functions/PyInterpretationFn.cs @@ -1,8 +1,7 @@ -using BotSharp.Abstraction.Conversations.Models; -using BotSharp.Abstraction.Functions; -using BotSharp.Abstraction.Interpreters.Models; +using BotSharp.Abstraction.Routing; using Microsoft.Extensions.Logging; using Python.Runtime; +using System.Runtime; using System.Text.Json; using System.Threading.Tasks; @@ -26,7 +25,40 @@ public class PyInterpretationFn : IFunctionCallback public async Task Execute(RoleDialogModel message) { - var args = JsonSerializer.Deserialize(message.FunctionArgs); + var agentService = _services.GetRequiredService(); + var convService = _services.GetRequiredService(); + var routingCtx = _services.GetRequiredService(); + + var args = JsonSerializer.Deserialize(message.FunctionArgs); + + var agent = await agentService.GetAgent(message.CurrentAgentId); + var inst = GetPyCodeGenerationInstruction(message.CurrentAgentId); + var innerAgent = new Agent + { + Id = agent.Id, + Name = agent.Name, + Instruction = inst, + LlmConfig = GetLlmConfig(), + TemplateDict = new Dictionary + { + { "user_requirement", args?.UserRquirement ?? string.Empty } + } + }; + + var dialogs = routingCtx.GetDialogs(); + if (dialogs.IsNullOrEmpty()) + { + dialogs = convService.GetDialogHistory(); + } + + dialogs.Add(new RoleDialogModel(AgentRole.User, "Please follow the instruction and chat context to generate valid python code.") + { + CurrentAgentId = message.CurrentAgentId, + MessageId = message.MessageId + }); + + var response = await GetChatCompletion(innerAgent, dialogs); + var ret = response.JsonContent(); using (Py.GIL()) { @@ -40,7 +72,7 @@ public class PyInterpretationFn : IFunctionCallback // Execute a simple Python script using var locals = new PyDict(); - PythonEngine.Exec(args.Script, null, locals); + PythonEngine.Exec(ret.PythonCode, null, locals); // Console.WriteLine($"Result from Python: {result}"); message.Content = stringIO.getvalue(); @@ -51,4 +83,74 @@ public class PyInterpretationFn : IFunctionCallback return true; } + + private async Task GetChatCompletion(Agent agent, List dialogs) + { + try + { + var (provider, model) = GetLlmProviderModel(); + var completion = CompletionProvider.GetChatCompletion(_services, provider: provider, model: model); + var response = await completion.GetChatCompletions(agent, dialogs); + return response.Content; + } + catch (Exception ex) + { + var error = $"Error when plotting chart. {ex.Message}"; + _logger.LogWarning(ex, error); + return error; + } + } + + private string GetPyCodeGenerationInstruction(string agentId) + { + var db = _services.GetRequiredService(); + var state = _services.GetRequiredService(); + + var templateContent = string.Empty; + var templateName = state.GetState("python_generate_template"); + + if (!string.IsNullOrEmpty(templateName)) + { + templateContent = db.GetAgentTemplate(agentId, templateName); + } + else + { + templateName = "util-code-python_generate_instruction"; + templateContent = db.GetAgentTemplate(BuiltInAgentId.UtilityAssistant, templateName); + } + + return templateContent; + } + + private (string, string) GetLlmProviderModel() + { + var provider = "openai"; + var model = "gpt-5"; + + var state = _services.GetRequiredService(); + provider = state.GetState("py_generator_llm_provider") + //.IfNullOrEmptyAs(_settings.ChartPlot?.LlmProvider) + .IfNullOrEmptyAs(provider); + model = state.GetState("py_generator_llm_model") + //.IfNullOrEmptyAs(_settings.ChartPlot?.LlmModel) + .IfNullOrEmptyAs(model); + + return (provider, model); + } + + private AgentLlmConfig GetLlmConfig() + { + var maxOutputTokens = 8192; + var reasoningEffortLevel = "minimal"; + + var state = _services.GetRequiredService(); + maxOutputTokens = int.TryParse(state.GetState("py_generator_max_output_tokens"), out var tokens) ? tokens : maxOutputTokens; + reasoningEffortLevel = state.GetState("py_generator_reasoning_effort_level").IfNullOrEmptyAs(reasoningEffortLevel); + + return new AgentLlmConfig + { + MaxOutputTokens = maxOutputTokens, + ReasoningEffortLevel = reasoningEffortLevel + }; + } } diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/InterpreterPlugin.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/InterpreterPlugin.cs index 7d195286..2e1e723b 100644 --- a/src/Plugins/BotSharp.Plugin.PythonInterpreter/InterpreterPlugin.cs +++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/InterpreterPlugin.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Interpreters.Settings; +using BotSharp.Abstraction.Settings; using BotSharp.Plugin.PythonInterpreter.Hooks; using Microsoft.AspNetCore.Builder; using Python.Runtime; @@ -15,6 +16,12 @@ public class InterpreterPlugin : IBotSharpAppPlugin public void RegisterDI(IServiceCollection services, IConfiguration config) { + services.AddSingleton(provider => + { + var settingService = provider.GetRequiredService(); + return settingService.Bind("Interpreter"); + }); + services.AddScoped(); } diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/LlmContext/LlmContextIn.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/LlmContext/LlmContextIn.cs new file mode 100644 index 00000000..bcac0e8b --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/LlmContext/LlmContextIn.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace BotSharp.Plugin.PythonInterpreter.LlmContext; + +public class LlmContextIn +{ + [JsonPropertyName("user_requirement")] + public string UserRquirement { get; set; } +} diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/LlmContext/LlmContextOut.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/LlmContext/LlmContextOut.cs new file mode 100644 index 00000000..b074a004 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/LlmContext/LlmContextOut.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace BotSharp.Plugin.PythonInterpreter.LlmContext; + +public class LlmContextOut +{ + [JsonPropertyName("python_code")] + public string PythonCode { get; set; } +} diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Using.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Using.cs index 8cc31aa1..00a172fa 100644 --- a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Using.cs +++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Using.cs @@ -14,5 +14,12 @@ global using BotSharp.Abstraction.Agents.Settings; global using BotSharp.Abstraction.Conversations; global using BotSharp.Abstraction.Functions.Models; global using BotSharp.Abstraction.Repositories; +global using BotSharp.Abstraction.Conversations.Models; +global using BotSharp.Abstraction.Functions; +global using BotSharp.Abstraction.Interpreters.Models; + + +global using BotSharp.Core.Infrastructures; global using BotSharp.Plugin.PythonInterpreter.Enums; +global using BotSharp.Plugin.PythonInterpreter.LlmContext; diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-code-python_interpreter.json b/src/Plugins/BotSharp.Plugin.PythonInterpreter/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-code-python_interpreter.json index ac2b2a91..ee5a708e 100644 --- a/src/Plugins/BotSharp.Plugin.PythonInterpreter/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-code-python_interpreter.json +++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-code-python_interpreter.json @@ -1,19 +1,14 @@ { - "name": "python_interpreter", - "description": "write and execute python code, print the result in Console", + "name": "util-code-python_interpreter", + "description": "If the user requests you generating python code to complete tasks, you can call this function to generate python code to execute.", "parameters": { "type": "object", "properties": { - "script": { + "user_requirement": { "type": "string", - "description": "python code" - }, - "language": { - "type": "string", - "enum": [ "python" ], - "description": "python code" + "description": "The requirement that user posted for generating python code." } }, - "required": [ "language", "script" ] + "required": [ "user_requirement" ] } } \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/util-code-python_interpreter.fn.liquid b/src/Plugins/BotSharp.Plugin.PythonInterpreter/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/util-code-python_interpreter.fn.liquid index 8dd2425f..9037aaff 100644 --- a/src/Plugins/BotSharp.Plugin.PythonInterpreter/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/util-code-python_interpreter.fn.liquid +++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/util-code-python_interpreter.fn.liquid @@ -1 +1 @@ -Write and execute Python script in python_interpreter function, and use python function print(a) to output the result in stand output. \ No newline at end of file +Please call function util-code-python_interpreter if user wants to generate python code to complete tasks. \ No newline at end of file