| 99 | maxkb_logger.error(f"Exception: {e}", exc_info=True) |
| 100 | |
| 101 | def exec_code(self, code_str, keywords, function_name=None): |
| 102 | _id = str(uuid.uuid7()) |
| 103 | action_function = ( |
| 104 | f"({function_name!a}, locals_v.get({function_name!a}))" if function_name else "locals_v.popitem()" |
| 105 | ) |
| 106 | set_run_user = ( |
| 107 | f"os.setgid({pwd.getpwnam(_run_user).pw_gid});os.setuid({pwd.getpwnam(_run_user).pw_uid});" |
| 108 | if _enable_sandbox |
| 109 | else "" |
| 110 | ) |
| 111 | _exec_code = f""" |
| 112 | try: |
| 113 | import os, sys, json |
| 114 | from contextlib import redirect_stdout |
| 115 | path_to_exclude = ['/opt/py3/lib/python3.11/site-packages', '/opt/maxkb-app/apps'] |
| 116 | sys.path = [p for p in sys.path if p not in path_to_exclude] |
| 117 | sys.path += {_sandbox_python_sys_path} |
| 118 | _id = os.environ.get("_ID") |
| 119 | locals_v = {{}} |
| 120 | keywords = {keywords} |
| 121 | globals_v = {{}} |
| 122 | {set_run_user} |
| 123 | os.environ.clear() |
| 124 | with redirect_stdout(open(os.devnull, 'w')): |
| 125 | exec({dedent(code_str)!a}, globals_v, locals_v) |
| 126 | f_name, f = {action_function} |
| 127 | globals_v.update(locals_v) |
| 128 | exec_result = f(**keywords) |
| 129 | sys.stdout.write("\\n" + _id) |
| 130 | json.dump({{'code':200,'msg':'success','data':exec_result}}, sys.stdout, default=str) |
| 131 | except Exception as e: |
| 132 | if isinstance(e, MemoryError): e = Exception("Cannot allocate more memory: exceeded the limit of {_process_limit_mem_mb} MB.") |
| 133 | sys.stdout.write("\\n" + _id) |
| 134 | json.dump({{'code':500,'msg':str(e),'data':None}}, sys.stdout, default=str) |
| 135 | sys.stdout.write("\\n" + _id + "__END__\\n") |
| 136 | sys.stdout.flush() |
| 137 | """ |
| 138 | maxkb_logger.debug(f"Tool execution({_id}) execute code: {_exec_code}") |
| 139 | with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=True) as f: |
| 140 | f.write(_exec_code) |
| 141 | f.flush() |
| 142 | with execution_timer(_id): |
| 143 | subprocess_result = self._exec(f.name, _id) |
| 144 | if subprocess_result.returncode != 0: |
| 145 | raise Exception(subprocess_result.stderr or subprocess_result.stdout or "Unknown exception occurred") |
| 146 | lines = subprocess_result.stdout.splitlines() |
| 147 | if len(lines) < 2 or lines[-1] != f"{_id}__END__": |
| 148 | raise Exception("Execution interrupted or tampered") |
| 149 | last_line = lines[-2] |
| 150 | if not last_line.startswith(_id): |
| 151 | raise Exception("No result found.") |
| 152 | result = json.loads(last_line[len(_id) :]) |
| 153 | if result.get("code") == 200: |
| 154 | return result.get("data") |
| 155 | raise Exception(result.get("msg") + (f"\n{subprocess_result.stderr}" if subprocess_result.stderr else "")) |
| 156 | |
| 157 | def _generate_mcp_server_code(self, _code, params, name=None, description=None, tool_id=None): |
| 158 | # 解析代码,提取导入语句和函数定义 |