2025-03-16 17:17:01 +08:00
|
|
|
|
/**
|
|
|
|
|
* @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>
|
2025-03-17 14:07:41 +08:00
|
|
|
|
#include <mutex>
|
2025-03-16 17:17:01 +08:00
|
|
|
|
|
|
|
|
|
// 检查是否找到Python
|
|
|
|
|
#ifdef PYTHON_FOUND
|
|
|
|
|
#include <Python.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @class python_interpreter
|
|
|
|
|
* @brief Python解释器类,用于执行Python代码
|
|
|
|
|
*/
|
|
|
|
|
class python_interpreter {
|
2025-03-17 14:07:41 +08:00
|
|
|
|
private:
|
|
|
|
|
// 互斥锁,确保Python解释器的线程安全
|
|
|
|
|
mutable std::mutex py_mutex;
|
|
|
|
|
bool is_initialized;
|
|
|
|
|
|
2025-03-16 17:17:01 +08:00
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* @brief 构造函数,初始化Python解释器
|
|
|
|
|
*/
|
2025-03-17 14:07:41 +08:00
|
|
|
|
python_interpreter() : is_initialized(false) {
|
2025-03-16 17:17:01 +08:00
|
|
|
|
#ifdef PYTHON_FOUND
|
2025-03-17 14:07:41 +08:00
|
|
|
|
try {
|
|
|
|
|
Py_Initialize();
|
|
|
|
|
if (Py_IsInitialized()) {
|
|
|
|
|
is_initialized = true;
|
|
|
|
|
// 初始化线程支持
|
|
|
|
|
PyEval_InitThreads();
|
|
|
|
|
// 释放GIL,允许其他线程获取
|
|
|
|
|
PyThreadState *_save = PyEval_SaveThread();
|
|
|
|
|
} else {
|
|
|
|
|
std::cerr << "Python解释器初始化失败" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
std::cerr << "Python解释器初始化异常: " << e.what() << std::endl;
|
|
|
|
|
}
|
2025-03-16 17:17:01 +08:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 析构函数,释放Python解释器
|
|
|
|
|
*/
|
|
|
|
|
~python_interpreter() {
|
|
|
|
|
#ifdef PYTHON_FOUND
|
2025-03-17 14:07:41 +08:00
|
|
|
|
if (is_initialized) {
|
|
|
|
|
std::lock_guard<std::mutex> lock(py_mutex);
|
|
|
|
|
Py_Finalize();
|
|
|
|
|
is_initialized = false;
|
|
|
|
|
}
|
2025-03-16 17:17:01 +08:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 执行Python代码
|
|
|
|
|
* @param input 包含Python代码的JSON对象
|
|
|
|
|
* @return 执行结果的JSON对象
|
|
|
|
|
*/
|
|
|
|
|
mcp::json forward(const mcp::json& input) const {
|
|
|
|
|
#ifdef PYTHON_FOUND
|
2025-03-17 14:07:41 +08:00
|
|
|
|
if (!is_initialized) {
|
|
|
|
|
return mcp::json{{"error", "Python解释器未正确初始化"}};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取GIL锁
|
|
|
|
|
std::lock_guard<std::mutex> lock(py_mutex);
|
|
|
|
|
PyGILState_STATE gstate = PyGILState_Ensure();
|
|
|
|
|
|
|
|
|
|
mcp::json result_json;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
if (input.contains("code") && input["code"].is_string()) {
|
|
|
|
|
std::string code = input["code"].get<std::string>();
|
|
|
|
|
|
|
|
|
|
// 获取主模块和字典
|
|
|
|
|
PyObject *main_module = PyImport_AddModule("__main__");
|
|
|
|
|
if (!main_module) {
|
|
|
|
|
PyGILState_Release(gstate);
|
|
|
|
|
return mcp::json{{"error", "无法获取Python主模块"}};
|
|
|
|
|
}
|
2025-03-16 17:17:01 +08:00
|
|
|
|
|
2025-03-17 14:07:41 +08:00
|
|
|
|
PyObject *main_dict = PyModule_GetDict(main_module);
|
|
|
|
|
if (!main_dict) {
|
|
|
|
|
PyGILState_Release(gstate);
|
|
|
|
|
return mcp::json{{"error", "无法获取Python主模块字典"}};
|
2025-03-16 17:17:01 +08:00
|
|
|
|
}
|
2025-03-17 14:07:41 +08:00
|
|
|
|
|
|
|
|
|
// 导入sys和io模块
|
|
|
|
|
PyObject *sys_module = PyImport_ImportModule("sys");
|
|
|
|
|
if (!sys_module) {
|
|
|
|
|
PyErr_Print();
|
|
|
|
|
PyGILState_Release(gstate);
|
|
|
|
|
return mcp::json{{"error", "无法导入sys模块"}};
|
2025-03-16 17:17:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-03-17 14:07:41 +08:00
|
|
|
|
PyObject *io_module = PyImport_ImportModule("io");
|
|
|
|
|
if (!io_module) {
|
|
|
|
|
Py_DECREF(sys_module);
|
|
|
|
|
PyErr_Print();
|
|
|
|
|
PyGILState_Release(gstate);
|
|
|
|
|
return mcp::json{{"error", "无法导入io模块"}};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取StringIO类
|
|
|
|
|
PyObject *string_io = PyObject_GetAttrString(io_module, "StringIO");
|
|
|
|
|
if (!string_io) {
|
|
|
|
|
Py_DECREF(io_module);
|
|
|
|
|
Py_DECREF(sys_module);
|
|
|
|
|
PyErr_Print();
|
|
|
|
|
PyGILState_Release(gstate);
|
|
|
|
|
return mcp::json{{"error", "无法获取StringIO类"}};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建StringIO对象
|
|
|
|
|
PyObject *sys_stdout = PyObject_CallObject(string_io, nullptr);
|
|
|
|
|
if (!sys_stdout) {
|
|
|
|
|
Py_DECREF(string_io);
|
|
|
|
|
Py_DECREF(io_module);
|
|
|
|
|
Py_DECREF(sys_module);
|
|
|
|
|
PyErr_Print();
|
|
|
|
|
PyGILState_Release(gstate);
|
|
|
|
|
return mcp::json{{"error", "无法创建stdout StringIO对象"}};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PyObject *sys_stderr = PyObject_CallObject(string_io, nullptr);
|
|
|
|
|
if (!sys_stderr) {
|
|
|
|
|
Py_DECREF(sys_stdout);
|
|
|
|
|
Py_DECREF(string_io);
|
|
|
|
|
Py_DECREF(io_module);
|
|
|
|
|
Py_DECREF(sys_module);
|
|
|
|
|
PyErr_Print();
|
|
|
|
|
PyGILState_Release(gstate);
|
|
|
|
|
return mcp::json{{"error", "无法创建stderr StringIO对象"}};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 保存原始的stdout和stderr
|
|
|
|
|
PyObject *old_stdout = PySys_GetObject("stdout");
|
|
|
|
|
PyObject *old_stderr = PySys_GetObject("stderr");
|
|
|
|
|
|
|
|
|
|
if (old_stdout) Py_INCREF(old_stdout);
|
|
|
|
|
if (old_stderr) Py_INCREF(old_stderr);
|
|
|
|
|
|
|
|
|
|
// 替换sys.stdout和sys.stderr
|
|
|
|
|
if (PySys_SetObject("stdout", sys_stdout) != 0 ||
|
|
|
|
|
PySys_SetObject("stderr", sys_stderr) != 0) {
|
|
|
|
|
Py_DECREF(sys_stderr);
|
|
|
|
|
Py_DECREF(sys_stdout);
|
|
|
|
|
Py_DECREF(string_io);
|
|
|
|
|
Py_DECREF(io_module);
|
|
|
|
|
Py_DECREF(sys_module);
|
|
|
|
|
PyErr_Print();
|
|
|
|
|
PyGILState_Release(gstate);
|
|
|
|
|
return mcp::json{{"error", "无法设置stdout/stderr重定向"}};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 执行Python代码
|
|
|
|
|
PyObject *result = PyRun_String(code.c_str(), Py_file_input, main_dict, main_dict);
|
|
|
|
|
if (!result) {
|
|
|
|
|
PyErr_Print();
|
|
|
|
|
}
|
|
|
|
|
Py_XDECREF(result);
|
|
|
|
|
|
|
|
|
|
// 获取输出和错误
|
|
|
|
|
PyObject *out_value = PyObject_CallMethod(sys_stdout, "getvalue", nullptr);
|
|
|
|
|
PyObject *err_value = PyObject_CallMethod(sys_stderr, "getvalue", nullptr);
|
|
|
|
|
|
|
|
|
|
std::string output, error;
|
|
|
|
|
|
|
|
|
|
// 安全地转换Python字符串到C++字符串
|
|
|
|
|
if (out_value && PyUnicode_Check(out_value)) {
|
|
|
|
|
output = PyUnicode_AsUTF8(out_value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (err_value && PyUnicode_Check(err_value)) {
|
|
|
|
|
error = PyUnicode_AsUTF8(err_value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 恢复原始的stdout和stderr
|
|
|
|
|
if (old_stdout) {
|
|
|
|
|
PySys_SetObject("stdout", old_stdout);
|
|
|
|
|
Py_DECREF(old_stdout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (old_stderr) {
|
|
|
|
|
PySys_SetObject("stderr", old_stderr);
|
|
|
|
|
Py_DECREF(old_stderr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 清理
|
|
|
|
|
Py_XDECREF(out_value);
|
|
|
|
|
Py_XDECREF(err_value);
|
|
|
|
|
Py_DECREF(sys_stdout);
|
|
|
|
|
Py_DECREF(sys_stderr);
|
|
|
|
|
Py_DECREF(string_io);
|
|
|
|
|
Py_DECREF(io_module);
|
|
|
|
|
Py_DECREF(sys_module);
|
|
|
|
|
|
|
|
|
|
// 准备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);
|
|
|
|
|
}
|
2025-03-16 17:17:01 +08:00
|
|
|
|
|
2025-03-17 14:07:41 +08:00
|
|
|
|
result_json["warning"] = "No output. Maybe try with print(" + last_line + ")?";
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
result_json["error"] = "Invalid parameters or code not provided";
|
|
|
|
|
}
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
result_json["error"] = std::string("Python执行异常: ") + e.what();
|
2025-03-16 17:17:01 +08:00
|
|
|
|
}
|
2025-03-17 14:07:41 +08:00
|
|
|
|
|
|
|
|
|
// 释放GIL
|
|
|
|
|
PyGILState_Release(gstate);
|
|
|
|
|
return result_json;
|
2025-03-16 17:17:01 +08:00
|
|
|
|
#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")) {
|
|
|
|
|
throw mcp::mcp_exception(mcp::error_code::invalid_params, "缺少'code'参数");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 使用Python解释器执行代码
|
|
|
|
|
mcp::json result = interpreter.forward(args);
|
|
|
|
|
|
|
|
|
|
return {{
|
|
|
|
|
{"type", "text"},
|
2025-03-17 14:07:41 +08:00
|
|
|
|
{"text", result.dump(2)}
|
2025-03-16 17:17:01 +08:00
|
|
|
|
}};
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
throw mcp::mcp_exception(mcp::error_code::internal_error,
|
|
|
|
|
"执行Python代码失败: " + std::string(e.what()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-17 14:07:41 +08:00
|
|
|
|
// Register the PythonExecute tool
|
2025-03-16 17:17:01 +08:00
|
|
|
|
void register_python_execute_tool(mcp::server& server) {
|
2025-03-17 14:07:41 +08:00
|
|
|
|
mcp::tool python_tool = mcp::tool_builder("python_execute")
|
|
|
|
|
.with_description("Execute Python code and return the result")
|
|
|
|
|
.with_string_param("code", "The Python code to execute", true)
|
2025-03-16 17:17:01 +08:00
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
server.register_tool(python_tool, python_execute_handler);
|
|
|
|
|
}
|