2025-09-29 06:20:25 +00:00
|
|
|
using BotSharp.Abstraction.Routing;
|
2024-08-12 19:22:47 +00:00
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
using Python.Runtime;
|
2025-09-29 06:20:25 +00:00
|
|
|
using System.Runtime;
|
2024-08-12 19:22:47 +00:00
|
|
|
using System.Text.Json;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace BotSharp.Plugin.PythonInterpreter.Functions;
|
|
|
|
|
|
2025-09-27 00:21:08 +00:00
|
|
|
public class PyInterpretationFn : IFunctionCallback
|
2024-08-12 19:22:47 +00:00
|
|
|
{
|
2025-09-27 00:21:08 +00:00
|
|
|
public string Name => "util-code-python_interpreter";
|
|
|
|
|
public string Indication => "Executing python code";
|
2024-08-12 19:22:47 +00:00
|
|
|
|
|
|
|
|
private readonly IServiceProvider _services;
|
2025-09-27 00:21:08 +00:00
|
|
|
private readonly ILogger<PyInterpretationFn> _logger;
|
2025-09-29 06:35:08 +00:00
|
|
|
private readonly PythonInterpreterSettings _settings;
|
2025-09-27 00:21:08 +00:00
|
|
|
|
|
|
|
|
public PyInterpretationFn(
|
|
|
|
|
IServiceProvider services,
|
2025-09-29 06:35:08 +00:00
|
|
|
ILogger<PyInterpretationFn> logger,
|
|
|
|
|
PythonInterpreterSettings settings)
|
2025-09-27 00:21:08 +00:00
|
|
|
{
|
|
|
|
|
_services = services;
|
|
|
|
|
_logger = logger;
|
2025-09-29 06:35:08 +00:00
|
|
|
_settings = settings;
|
2025-09-27 00:21:08 +00:00
|
|
|
}
|
2024-08-12 19:22:47 +00:00
|
|
|
|
|
|
|
|
public async Task<bool> Execute(RoleDialogModel message)
|
|
|
|
|
{
|
2025-09-29 06:20:25 +00:00
|
|
|
var agentService = _services.GetRequiredService<IAgentService>();
|
|
|
|
|
var convService = _services.GetRequiredService<IConversationService>();
|
|
|
|
|
var routingCtx = _services.GetRequiredService<IRoutingContext>();
|
|
|
|
|
|
|
|
|
|
var args = JsonSerializer.Deserialize<LlmContextIn>(message.FunctionArgs);
|
|
|
|
|
|
|
|
|
|
var agent = await agentService.GetAgent(message.CurrentAgentId);
|
2025-09-29 06:35:08 +00:00
|
|
|
var inst = GetPyCodeInterpreterInstruction(message.CurrentAgentId);
|
2025-09-29 06:20:25 +00:00
|
|
|
var innerAgent = new Agent
|
|
|
|
|
{
|
|
|
|
|
Id = agent.Id,
|
|
|
|
|
Name = agent.Name,
|
|
|
|
|
Instruction = inst,
|
|
|
|
|
LlmConfig = GetLlmConfig(),
|
|
|
|
|
TemplateDict = new Dictionary<string, object>
|
|
|
|
|
{
|
|
|
|
|
{ "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<LlmContextOut>();
|
2024-08-12 19:22:47 +00:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
// Execute a simple Python script
|
|
|
|
|
using var locals = new PyDict();
|
2025-09-29 06:20:25 +00:00
|
|
|
PythonEngine.Exec(ret.PythonCode, null, locals);
|
2024-08-12 19:22:47 +00:00
|
|
|
|
|
|
|
|
// Console.WriteLine($"Result from Python: {result}");
|
|
|
|
|
message.Content = stringIO.getvalue();
|
|
|
|
|
|
|
|
|
|
// Restore the original stdout
|
|
|
|
|
sys.stdout = sys.__stdout__;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2025-09-29 06:20:25 +00:00
|
|
|
|
|
|
|
|
private async Task<string> GetChatCompletion(Agent agent, List<RoleDialogModel> 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)
|
|
|
|
|
{
|
2025-09-29 06:35:08 +00:00
|
|
|
var error = $"Error when generating python code. {ex.Message}";
|
2025-09-29 06:20:25 +00:00
|
|
|
_logger.LogWarning(ex, error);
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-29 06:35:08 +00:00
|
|
|
private string GetPyCodeInterpreterInstruction(string agentId)
|
2025-09-29 06:20:25 +00:00
|
|
|
{
|
|
|
|
|
var db = _services.GetRequiredService<IBotSharpRepository>();
|
|
|
|
|
var state = _services.GetRequiredService<IConversationStateService>();
|
|
|
|
|
|
|
|
|
|
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<IConversationStateService>();
|
2025-09-29 06:35:08 +00:00
|
|
|
provider = state.GetState("py_intepreter_llm_provider")
|
2025-09-29 06:20:25 +00:00
|
|
|
//.IfNullOrEmptyAs(_settings.ChartPlot?.LlmProvider)
|
|
|
|
|
.IfNullOrEmptyAs(provider);
|
2025-09-29 06:35:08 +00:00
|
|
|
model = state.GetState("py_intepreter_llm_model")
|
2025-09-29 06:20:25 +00:00
|
|
|
//.IfNullOrEmptyAs(_settings.ChartPlot?.LlmModel)
|
|
|
|
|
.IfNullOrEmptyAs(model);
|
|
|
|
|
|
|
|
|
|
return (provider, model);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private AgentLlmConfig GetLlmConfig()
|
|
|
|
|
{
|
|
|
|
|
var maxOutputTokens = 8192;
|
|
|
|
|
var reasoningEffortLevel = "minimal";
|
|
|
|
|
|
|
|
|
|
var state = _services.GetRequiredService<IConversationStateService>();
|
2025-09-29 06:35:08 +00:00
|
|
|
maxOutputTokens = int.TryParse(state.GetState("py_intepreter_max_output_tokens"), out var tokens) ? tokens : maxOutputTokens;
|
|
|
|
|
reasoningEffortLevel = state.GetState("py_intepreter_reasoning_effort_level").IfNullOrEmptyAs(reasoningEffortLevel);
|
2025-09-29 06:20:25 +00:00
|
|
|
|
|
|
|
|
return new AgentLlmConfig
|
|
|
|
|
{
|
|
|
|
|
MaxOutputTokens = maxOutputTokens,
|
|
|
|
|
ReasoningEffortLevel = reasoningEffortLevel
|
|
|
|
|
};
|
|
|
|
|
}
|
2024-08-12 19:22:47 +00:00
|
|
|
}
|