refine py code generation
This commit is contained in:
parent
09c008f76f
commit
9abe315952
|
|
@ -1,10 +0,0 @@
|
|||
namespace BotSharp.Abstraction.Interpreters.Models;
|
||||
|
||||
public class InterpretationRequest
|
||||
{
|
||||
[JsonPropertyName("script")]
|
||||
public string Script { get; set; } = null!;
|
||||
|
||||
[JsonPropertyName("language")]
|
||||
public string Language { get; set; } = null!;
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
namespace BotSharp.Abstraction.Interpreters.Settings;
|
||||
|
||||
public class InterpreterSettings
|
||||
{
|
||||
public PythonInterpreterSetting Python { get; set; }
|
||||
}
|
||||
|
||||
public class PythonInterpreterSetting
|
||||
{
|
||||
public string PythonDLL { get; set; }
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ using BotSharp.Abstraction.Settings;
|
|||
using BotSharp.Abstraction.Options;
|
||||
using BotSharp.Abstraction.Messaging.JsonConverters;
|
||||
using BotSharp.Abstraction.Users.Settings;
|
||||
using BotSharp.Abstraction.Interpreters.Settings;
|
||||
using BotSharp.Abstraction.Infrastructures;
|
||||
using BotSharp.Core.Processors;
|
||||
using StackExchange.Redis;
|
||||
|
|
|
|||
|
|
@ -11,16 +11,14 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\util-code-python_interpreter.json" />
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-code-python_interpreter.fn.liquid" />
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-code-python_generate_instruction.liquid" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\util-code-python_interpreter.json">
|
||||
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\util-code-python_programmer.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-code-python_interpreter.fn.liquid">
|
||||
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-code-python_programmer.fn.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-code-python_generate_instruction.liquid">
|
||||
|
|
|
|||
|
|
@ -2,5 +2,5 @@ namespace BotSharp.Plugin.PythonInterpreter.Enums;
|
|||
|
||||
public class UtilityName
|
||||
{
|
||||
public const string PythonInterpreter = "python-interpreter";
|
||||
public const string PythonProgrammer = "python-programmer";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,22 @@
|
|||
using BotSharp.Abstraction.Routing;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Python.Runtime;
|
||||
using System.Runtime;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BotSharp.Plugin.PythonInterpreter.Functions;
|
||||
|
||||
public class PyInterpretationFn : IFunctionCallback
|
||||
public class PyProgrammerFn : IFunctionCallback
|
||||
{
|
||||
public string Name => "util-code-python_interpreter";
|
||||
public string Indication => "Executing python code";
|
||||
public string Name => "util-code-python_programmer";
|
||||
public string Indication => "Programming and executing code";
|
||||
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly ILogger<PyInterpretationFn> _logger;
|
||||
private readonly ILogger<PyProgrammerFn> _logger;
|
||||
private readonly PythonInterpreterSettings _settings;
|
||||
|
||||
public PyInterpretationFn(
|
||||
public PyProgrammerFn(
|
||||
IServiceProvider services,
|
||||
ILogger<PyInterpretationFn> logger,
|
||||
ILogger<PyProgrammerFn> logger,
|
||||
PythonInterpreterSettings settings)
|
||||
{
|
||||
_services = services;
|
||||
|
|
@ -44,6 +42,7 @@ public class PyInterpretationFn : IFunctionCallback
|
|||
LlmConfig = GetLlmConfig(),
|
||||
TemplateDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "python_version", _settings.PythonVersion ?? "3.11" },
|
||||
{ "user_requirement", args?.UserRquirement ?? string.Empty }
|
||||
}
|
||||
};
|
||||
|
|
@ -54,6 +53,8 @@ public class PyInterpretationFn : IFunctionCallback
|
|||
dialogs = convService.GetDialogHistory();
|
||||
}
|
||||
|
||||
var messageLimit = _settings.CodeGeneration?.MessageLimit > 0 ? _settings.CodeGeneration.MessageLimit.Value : 50;
|
||||
dialogs = dialogs.TakeLast(messageLimit).ToList();
|
||||
dialogs.Add(new RoleDialogModel(AgentRole.User, "Please follow the instruction and chat context to generate valid python code.")
|
||||
{
|
||||
CurrentAgentId = message.CurrentAgentId,
|
||||
|
|
@ -63,25 +64,51 @@ public class PyInterpretationFn : IFunctionCallback
|
|||
var response = await GetChatCompletion(innerAgent, dialogs);
|
||||
var ret = response.JsonContent<LlmContextOut>();
|
||||
|
||||
using (Py.GIL())
|
||||
try
|
||||
{
|
||||
// Import necessary Python modules
|
||||
dynamic sys = Py.Import("sys");
|
||||
dynamic io = Py.Import("io");
|
||||
using (Py.GIL())
|
||||
{
|
||||
// Import necessary Python modules
|
||||
dynamic sys = Py.Import("sys");
|
||||
dynamic io = Py.Import("io");
|
||||
|
||||
// Redirect standard output to capture it
|
||||
dynamic stringIO = io.StringIO();
|
||||
sys.stdout = stringIO;
|
||||
// Redirect standard output/error to capture it
|
||||
dynamic stringIO = io.StringIO();
|
||||
sys.stdout = stringIO;
|
||||
sys.stderr = stringIO;
|
||||
|
||||
// Execute a simple Python script
|
||||
using var locals = new PyDict();
|
||||
PythonEngine.Exec(ret.PythonCode, null, locals);
|
||||
// Set global items
|
||||
using var globals = new PyDict();
|
||||
if (ret.PythonCode?.Contains("__main__") == true)
|
||||
{
|
||||
globals.SetItem("__name__", new PyString("__main__"));
|
||||
}
|
||||
|
||||
// Console.WriteLine($"Result from Python: {result}");
|
||||
message.Content = stringIO.getvalue();
|
||||
// Execute Python script
|
||||
PythonEngine.Exec(ret.PythonCode, globals);
|
||||
|
||||
// Restore the original stdout
|
||||
sys.stdout = sys.__stdout__;
|
||||
// Get result
|
||||
var result = stringIO.getvalue().ToString();
|
||||
message.Content = result;
|
||||
message.RichContent = new RichContent<IRichMessage>
|
||||
{
|
||||
Recipient = new Recipient { Id = convService.ConversationId },
|
||||
Message = new ProgramCodeTemplateMessage
|
||||
{
|
||||
Text = ret.PythonCode ?? string.Empty,
|
||||
Language = "python"
|
||||
}
|
||||
};
|
||||
message.StopCompletion = true;
|
||||
|
||||
// Restore the original stdout/stderr
|
||||
sys.stdout = sys.__stdout__;
|
||||
sys.stderr = sys.__stderr__;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"Error when executing python code.");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -132,10 +159,10 @@ public class PyInterpretationFn : IFunctionCallback
|
|||
|
||||
var state = _services.GetRequiredService<IConversationStateService>();
|
||||
provider = state.GetState("py_intepreter_llm_provider")
|
||||
//.IfNullOrEmptyAs(_settings.ChartPlot?.LlmProvider)
|
||||
.IfNullOrEmptyAs(_settings.CodeGeneration?.LlmProvider)
|
||||
.IfNullOrEmptyAs(provider);
|
||||
model = state.GetState("py_intepreter_llm_model")
|
||||
//.IfNullOrEmptyAs(_settings.ChartPlot?.LlmModel)
|
||||
.IfNullOrEmptyAs(_settings.CodeGeneration?.LlmModel)
|
||||
.IfNullOrEmptyAs(model);
|
||||
|
||||
return (provider, model);
|
||||
|
|
@ -143,8 +170,8 @@ public class PyInterpretationFn : IFunctionCallback
|
|||
|
||||
private AgentLlmConfig GetLlmConfig()
|
||||
{
|
||||
var maxOutputTokens = 8192;
|
||||
var reasoningEffortLevel = "minimal";
|
||||
var maxOutputTokens = _settings?.CodeGeneration?.MaxOutputTokens ?? 8192;
|
||||
var reasoningEffortLevel = _settings?.CodeGeneration?.ReasoningEffortLevel ?? "minimal";
|
||||
|
||||
var state = _services.GetRequiredService<IConversationStateService>();
|
||||
maxOutputTokens = int.TryParse(state.GetState("py_intepreter_max_output_tokens"), out var tokens) ? tokens : maxOutputTokens;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
namespace BotSharp.Plugin.PythonInterpreter.Hooks;
|
||||
|
||||
public class PyProgrammerUtilityHook : IAgentUtilityHook
|
||||
{
|
||||
private const string PY_PROGRAMMER_FN = "util-code-python_programmer";
|
||||
|
||||
public void AddUtilities(List<AgentUtility> utilities)
|
||||
{
|
||||
var utility = new AgentUtility()
|
||||
{
|
||||
Category = "code",
|
||||
Name = UtilityName.PythonProgrammer,
|
||||
Items = [
|
||||
new UtilityItem
|
||||
{
|
||||
FunctionName = PY_PROGRAMMER_FN,
|
||||
TemplateName = $"{PY_PROGRAMMER_FN}.fn"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
utilities.Add(utility);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
namespace BotSharp.Plugin.PythonInterpreter.Hooks;
|
||||
|
||||
public class PythonInterpreterUtilityHook : IAgentUtilityHook
|
||||
{
|
||||
private const string PY_INTERPRETER_FN = "util-code-python_interpreter";
|
||||
|
||||
public void AddUtilities(List<AgentUtility> utilities)
|
||||
{
|
||||
var utility = new AgentUtility()
|
||||
{
|
||||
Category = "coding",
|
||||
Name = UtilityName.PythonInterpreter,
|
||||
Items = [
|
||||
new UtilityItem
|
||||
{
|
||||
FunctionName = PY_INTERPRETER_FN,
|
||||
TemplateName = $"{PY_INTERPRETER_FN}.fn"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
utilities.Add(utility);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using BotSharp.Abstraction.Settings;
|
||||
using BotSharp.Plugin.PythonInterpreter.Hooks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Python.Runtime;
|
||||
using System.IO;
|
||||
|
||||
|
|
@ -13,15 +13,15 @@ public class PythonInterpreterPlugin : IBotSharpAppPlugin
|
|||
public string Description => "Python Interpreter enables AI to write and execute Python code within a secure, sandboxed environment.";
|
||||
public string? IconUrl => "https://static.vecteezy.com/system/resources/previews/012/697/295/non_2x/3d-python-programming-language-logo-free-png.png";
|
||||
|
||||
private nint _pyState;
|
||||
|
||||
public void RegisterDI(IServiceCollection services, IConfiguration config)
|
||||
{
|
||||
services.AddSingleton(provider =>
|
||||
{
|
||||
var settingService = provider.GetRequiredService<ISettingService>();
|
||||
return settingService.Bind<PythonInterpreterSettings>("PythonInterpreter");
|
||||
});
|
||||
var settings = new PythonInterpreterSettings();
|
||||
config.Bind("PythonInterpreter", settings);
|
||||
services.AddSingleton(x => settings);
|
||||
|
||||
services.AddScoped<IAgentUtilityHook, PythonInterpreterUtilityHook>();
|
||||
services.AddScoped<IAgentUtilityHook, PyProgrammerUtilityHook>();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
|
|
@ -33,14 +33,17 @@ public class PythonInterpreterPlugin : IBotSharpAppPlugin
|
|||
{
|
||||
Runtime.PythonDLL = settings.DllLocation;
|
||||
PythonEngine.Initialize();
|
||||
PythonEngine.BeginAllowThreads();
|
||||
_pyState = PythonEngine.BeginAllowThreads();
|
||||
|
||||
var lifetime = app.ApplicationServices.GetRequiredService<IHostApplicationLifetime>();
|
||||
lifetime.ApplicationStopping.Register(() => {
|
||||
PythonEngine.EndAllowThreads(_pyState);
|
||||
PythonEngine.Shutdown();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Serilog.Log.Error("Python DLL found at {PythonDLL}", settings.DllLocation);
|
||||
Serilog.Log.Error($"Python DLL found at {settings.DllLocation}");
|
||||
}
|
||||
|
||||
// Shut down the Python engine
|
||||
// PythonEngine.Shutdown();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
using BotSharp.Abstraction.Models;
|
||||
|
||||
namespace BotSharp.Plugin.PythonInterpreter.Settings;
|
||||
|
||||
public class PythonInterpreterSettings
|
||||
{
|
||||
public string DllLocation { get; set; }
|
||||
public string PythonVersion { get; set; }
|
||||
public CodeGenerationSetting? CodeGeneration { get; set; }
|
||||
}
|
||||
|
||||
public class CodeGenerationSetting : LlmConfigBase
|
||||
{
|
||||
public int? MessageLimit { get; set; }
|
||||
}
|
||||
|
|
@ -16,6 +16,10 @@ 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.Messaging;
|
||||
global using BotSharp.Abstraction.Messaging.Models.RichContent;
|
||||
global using BotSharp.Abstraction.Messaging.Models.RichContent.Template;
|
||||
global using BotSharp.Abstraction.Routing;
|
||||
|
||||
global using BotSharp.Core.Infrastructures;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"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.",
|
||||
"description": "If user's requirement can be fulfilled by python code, you can call this function to generate python code to execute.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
You are a Python code generator that can produce python code to fulfill user's requirement.
|
||||
Please read "User Requirement" and the chat context, and then generate valid python code that can fulfill user's requirement.
|
||||
|
||||
You must strictly follow the "Hard Requirements", "Code Requirements", and "Response Format" below.
|
||||
|
||||
=== User Requirement ===
|
||||
{{ user_requirement }}
|
||||
|
||||
|
||||
***** Hard Requirements *****
|
||||
1. Your output python code must be well constructed inside one or multiple functions.
|
||||
2. You must not include any code, explanations, or comments outside these functions.
|
||||
3. Do not include explanations, comments outside code.
|
||||
4. You must use print() once to output the final result only. Do not print intermediate values, logs, or debug info.
|
||||
5. If randomness is required, set a fixed seed inside a function.
|
||||
|
||||
|
||||
***** Code Requirements *****
|
||||
1. Structure
|
||||
a). You need to create small and focused functions.
|
||||
b). You need to include a main() function to orchestrates these steps.
|
||||
c). You must only call main() in "if __name__ == '__main__'" block.
|
||||
2. Data type & Validation
|
||||
a). When unsure about a variable’s type, check it at runtime (e.g., isinstance) before applying methods.
|
||||
b). Validate inputs and handle edge cases, such as empty lists, division by zero, out-of-range values.
|
||||
c). Except the main() function, it is preferable to generate functions that accept parameters and return values.
|
||||
3. Error handling
|
||||
a). If necessary, use try/except block inside main() to catch any errors and produce a single final printed message.
|
||||
4. Output
|
||||
a). You must print the final result once in main().
|
||||
5. Compatibility
|
||||
a). You must keep the code compatible with "Python {{ python_version }}"
|
||||
|
||||
|
||||
***** Response Format *****
|
||||
You must output the response in the following JSON format:
|
||||
{
|
||||
"python_code": "The python code that can fulfill user's request."
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
Please call function util-code-python_interpreter if user wants to generate python code to complete tasks.
|
||||
|
|
@ -0,0 +1 @@
|
|||
Please call function util-code-python_interpreter if you think it is necessary to fulfill user's request through python code.
|
||||
|
|
@ -488,7 +488,8 @@
|
|||
"LlmProvider": "openai",
|
||||
"LlmModel": "gpt-5",
|
||||
"MaxOutputTokens": 8192,
|
||||
"ReasoningEffortLevel": "minimal"
|
||||
"ReasoningEffortLevel": "minimal",
|
||||
"MessageLimit": 50
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -565,7 +566,15 @@
|
|||
},
|
||||
|
||||
"PythonInterpreter": {
|
||||
"DllLocation": "C:/Users/xxx/AppData/Local/Programs/Python/Python313/python313.dll"
|
||||
"DllLocation": "C:/Users/xxx/AppData/Local/Programs/Python/Python313/python313.dll",
|
||||
"PythonVersion": "3.13",
|
||||
"CodeGeneration": {
|
||||
"LlmProvider": "openai",
|
||||
"LlmModel": "gpt-5",
|
||||
"MaxOutputTokens": 8192,
|
||||
"ReasoningEffortLevel": "minimal",
|
||||
"MessageLimit": 50
|
||||
}
|
||||
},
|
||||
|
||||
"RealtimeModel": {
|
||||
|
|
|
|||
Loading…
Reference in a new issue