179 lines
5.8 KiB
C++
179 lines
5.8 KiB
C++
|
/**
|
|||
|
* @file python_execute.cpp
|
|||
|
* @brief OpenManus Python执行工具实现
|
|||
|
*
|
|||
|
* 这个文件实现了OpenManus的Python执行工具,使用Python.h直接调用Python解释器。
|
|||
|
*/
|
|||
|
|
|||
|
#include "mcp/include/mcp_server.h"
|
|||
|
#include "mcp/include/mcp_tool.h"
|
|||
|
#include "mcp/include/mcp_resource.h"
|
|||
|
|
|||
|
#include <iostream>
|
|||
|
#include <string>
|
|||
|
#include <memory>
|
|||
|
#include <stdexcept>
|
|||
|
|
|||
|
// 检查是否找到Python
|
|||
|
#ifdef PYTHON_FOUND
|
|||
|
#include <Python.h>
|
|||
|
#endif
|
|||
|
|
|||
|
/**
|
|||
|
* @class python_interpreter
|
|||
|
* @brief Python解释器类,用于执行Python代码
|
|||
|
*/
|
|||
|
class python_interpreter {
|
|||
|
public:
|
|||
|
/**
|
|||
|
* @brief 构造函数,初始化Python解释器
|
|||
|
*/
|
|||
|
python_interpreter() {
|
|||
|
#ifdef PYTHON_FOUND
|
|||
|
Py_Initialize();
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief 析构函数,释放Python解释器
|
|||
|
*/
|
|||
|
~python_interpreter() {
|
|||
|
#ifdef PYTHON_FOUND
|
|||
|
Py_Finalize();
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief 执行Python代码
|
|||
|
* @param input 包含Python代码的JSON对象
|
|||
|
* @return 执行结果的JSON对象
|
|||
|
*/
|
|||
|
mcp::json forward(const mcp::json& input) const {
|
|||
|
#ifdef PYTHON_FOUND
|
|||
|
if (input.contains("code") && input["code"].is_string()) {
|
|||
|
std::string code = input["code"].get<std::string>();
|
|||
|
|
|||
|
// Create scope to manage Python objects automatically
|
|||
|
PyObject *main_module = PyImport_AddModule("__main__");
|
|||
|
PyObject *main_dict = PyModule_GetDict(main_module);
|
|||
|
PyObject *sys_module = PyImport_ImportModule("sys");
|
|||
|
PyObject *io_module = PyImport_ImportModule("io");
|
|||
|
PyObject *string_io = PyObject_GetAttrString(io_module, "StringIO");
|
|||
|
PyObject *sys_stdout = PyObject_CallObject(string_io, nullptr);
|
|||
|
PyObject *sys_stderr = PyObject_CallObject(string_io, nullptr);
|
|||
|
|
|||
|
// Replace sys.stdout and sys.stderr with our StringIO objects
|
|||
|
PySys_SetObject("stdout", sys_stdout);
|
|||
|
PySys_SetObject("stderr", sys_stderr);
|
|||
|
|
|||
|
// Execute the Python code
|
|||
|
PyObject *result = PyRun_String(code.c_str(), Py_file_input, main_dict, main_dict);
|
|||
|
if (!result) {
|
|||
|
PyErr_Print();
|
|||
|
}
|
|||
|
Py_XDECREF(result);
|
|||
|
|
|||
|
// Fetch the output and error from the StringIO object
|
|||
|
PyObject *out_value = PyObject_CallMethod(sys_stdout, "getvalue", nullptr);
|
|||
|
PyObject *err_value = PyObject_CallMethod(sys_stderr, "getvalue", nullptr);
|
|||
|
|
|||
|
// Convert Python string to C++ string
|
|||
|
std::string output = PyUnicode_AsUTF8(out_value);
|
|||
|
std::string error = PyUnicode_AsUTF8(err_value);
|
|||
|
|
|||
|
// Restore the original sys.stdout and sys.stderr
|
|||
|
PySys_SetObject("stdout", PySys_GetObject("stdout"));
|
|||
|
PySys_SetObject("stderr", PySys_GetObject("stderr"));
|
|||
|
|
|||
|
// Clean up
|
|||
|
Py_DECREF(sys_stdout);
|
|||
|
Py_DECREF(sys_stderr);
|
|||
|
Py_DECREF(string_io);
|
|||
|
Py_DECREF(io_module);
|
|||
|
Py_DECREF(sys_module);
|
|||
|
|
|||
|
// Prepare JSON output
|
|||
|
mcp::json result_json;
|
|||
|
if (!output.empty()) {
|
|||
|
result_json["output"] = output;
|
|||
|
}
|
|||
|
if (!error.empty()) {
|
|||
|
result_json["error"] = error;
|
|||
|
}
|
|||
|
|
|||
|
if (result_json.empty()) {
|
|||
|
std::string last_line;
|
|||
|
std::istringstream code_stream(code);
|
|||
|
while (std::getline(code_stream, last_line, '\n')) {}
|
|||
|
size_t pos = last_line.find_last_of(';') + 1;
|
|||
|
pos = last_line.find("=") + 1;
|
|||
|
while (pos < last_line.size() && isblank(last_line[pos])) {
|
|||
|
pos++;
|
|||
|
}
|
|||
|
if (pos != std::string::npos) {
|
|||
|
last_line = last_line.substr(pos);
|
|||
|
}
|
|||
|
|
|||
|
return mcp::json{{"warning", "No output. Maybe try with print(" + last_line + ")?"}};
|
|||
|
}
|
|||
|
|
|||
|
return result_json;
|
|||
|
} else {
|
|||
|
return mcp::json{{"error", "Invalid parameters or code not provided"}};
|
|||
|
}
|
|||
|
#else
|
|||
|
return mcp::json{{"error", "Python interpreter not available"}};
|
|||
|
#endif
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
// 全局Python解释器实例
|
|||
|
static python_interpreter interpreter;
|
|||
|
|
|||
|
// Python执行工具处理函数
|
|||
|
mcp::json python_execute_handler(const mcp::json& args) {
|
|||
|
if (!args.contains("code")) {
|
|||
|
std::cout << args.dump() << std::endl;
|
|||
|
throw mcp::mcp_exception(mcp::error_code::invalid_params, "缺少'code'参数");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
// 使用Python解释器执行代码
|
|||
|
mcp::json result = interpreter.forward(args);
|
|||
|
|
|||
|
// 格式化输出结果
|
|||
|
std::string output;
|
|||
|
if (result.contains("output")) {
|
|||
|
output += result["output"].get<std::string>();
|
|||
|
}
|
|||
|
if (result.contains("error")) {
|
|||
|
output += result["error"].get<std::string>();
|
|||
|
}
|
|||
|
if (result.contains("warning")) {
|
|||
|
output += result["warning"].get<std::string>();
|
|||
|
}
|
|||
|
|
|||
|
if (output.empty()) {
|
|||
|
output = "Executed successfully but w/o output. Maybe you should print more information.";
|
|||
|
}
|
|||
|
|
|||
|
return {{
|
|||
|
{"type", "text"},
|
|||
|
{"text", output}
|
|||
|
}};
|
|||
|
} catch (const std::exception& e) {
|
|||
|
throw mcp::mcp_exception(mcp::error_code::internal_error,
|
|||
|
"执行Python代码失败: " + std::string(e.what()));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 注册Python执行工具的函数
|
|||
|
void register_python_execute_tool(mcp::server& server) {
|
|||
|
// 注册PythonExecute工具
|
|||
|
mcp::tool python_tool = mcp::tool_builder("PythonExecute")
|
|||
|
.with_description("执行Python代码并返回结果")
|
|||
|
.with_string_param("code", "要执行的Python代码", true)
|
|||
|
.build();
|
|||
|
|
|||
|
server.register_tool(python_tool, python_execute_handler);
|
|||
|
}
|