// retoor #include "tool.h" #include "r_config.h" #include "bash_executor.h" #include "markdown.h" #include #include #include #include #include #include static struct json_object *python_execute_get_description(void); static char *python_execute_execute(tool_t *self, struct json_object *args); static void python_execute_print_action(const char *name, struct json_object *args); static struct json_object *python_status_get_description(void); static char *python_status_execute(tool_t *self, struct json_object *args); static struct json_object *python_terminate_get_description(void); static char *python_terminate_execute(tool_t *self, struct json_object *args); static const tool_vtable_t python_execute_vtable = { .get_description = python_execute_get_description, .execute = python_execute_execute, .print_action = python_execute_print_action }; static const tool_vtable_t python_status_vtable = { .get_description = python_status_get_description, .execute = python_status_execute, .print_action = NULL }; static const tool_vtable_t python_terminate_vtable = { .get_description = python_terminate_get_description, .execute = python_terminate_execute, .print_action = NULL }; static tool_t python_execute_tool = { .vtable = &python_execute_vtable, .name = "python_execute" }; static tool_t python_status_tool = { .vtable = &python_status_vtable, .name = "python_get_status" }; static tool_t python_terminate_tool = { .vtable = &python_terminate_vtable, .name = "python_terminate" }; tool_t *tool_python_execute_create(void) { return &python_execute_tool; } tool_t *tool_python_get_status_create(void) { return &python_status_tool; } tool_t *tool_python_terminate_create(void) { return &python_terminate_tool; } static void python_execute_print_action(const char *name, struct json_object *args) { (void)name; struct json_object *source; if (json_object_object_get_ex(args, "source", &source)) { const char *src = json_object_get_string(source); fprintf(stderr, " \033[1;34m┌─── Python Source Code ─────────────────────────────────────\033[0m\n"); char *copy = strdup(src); char *line; char *saveptr; int line_num = 1; line = strtok_r(copy, "\n", &saveptr); while (line) { fprintf(stderr, " \033[1;34m│\033[0m \033[2m%3d |\033[0m ", line_num++); highlight_code(line); fprintf(stderr, "\033[0m\n"); line = strtok_r(NULL, "\n", &saveptr); } fprintf(stderr, " \033[1;34m└────────────────────────────────────────────────────────────\033[0m\n"); free(copy); } } static char *python_execute_execute(tool_t *self, struct json_object *args) { (void)self; struct json_object *source_obj, *timeout_obj, *async_obj; if (!json_object_object_get_ex(args, "source", &source_obj)) return strdup("Error: missing 'source'"); int timeout = 30; if (json_object_object_get_ex(args, "timeout", &timeout_obj)) timeout = json_object_get_int(timeout_obj); bool async = false; if (json_object_object_get_ex(args, "async", &async_obj)) async = json_object_get_boolean(async_obj); const char *source_code = json_object_get_string(source_obj); char tmp_file[] = "/tmp/r_python_XXXXXX.py"; int fd = mkstemps(tmp_file, 3); if (fd == -1) return strdup("Error: failed to create temp python file"); dprintf(fd, "%s\n", source_code); close(fd); char cmd[4096]; snprintf(cmd, sizeof(cmd), "python3 '%s'; ret=$?; rm '%s'; exit $ret", tmp_file, tmp_file); r_process_result_t *res = r_bash_execute_ext(cmd, timeout, async); struct json_object *root = json_object_new_object(); json_object_object_add(root, "pid", json_object_new_int(res->pid)); json_object_object_add(root, "output", json_object_new_string(res->output)); json_object_object_add(root, "is_running", json_object_new_boolean(res->is_running)); json_object_object_add(root, "timed_out", json_object_new_boolean(res->timed_out)); if (!res->is_running) { json_object_object_add(root, "exit_status", json_object_new_int(res->exit_status)); } char *out_str = strdup(json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); json_object_put(root); r_process_result_free(res); return out_str; } static char *python_status_execute(tool_t *self, struct json_object *args) { (void)self; struct json_object *pid_obj; if (!json_object_object_get_ex(args, "pid", &pid_obj)) return strdup("Error: missing 'pid'"); int pid = json_object_get_int(pid_obj); int status; bool running = true; int exit_status = -1; pid_t ret = waitpid(pid, &status, WNOHANG); if (ret == pid) { running = false; exit_status = WIFEXITED(status) ? WEXITSTATUS(status) : -1; } else if (ret == -1) { running = (kill(pid, 0) == 0); } char log_path[256]; snprintf(log_path, sizeof(log_path), "/tmp/r_process_%d.log", pid); char *content = NULL; FILE *f = fopen(log_path, "r"); if (f) { fseek(f, 0, SEEK_END); long size = ftell(f); rewind(f); if (size >= 0) { content = malloc((size_t)size + 1); if (content) { size_t rs = fread(content, 1, (size_t)size, f); content[rs] = '\0'; } } fclose(f); } struct json_object *root = json_object_new_object(); json_object_object_add(root, "pid", json_object_new_int(pid)); json_object_object_add(root, "is_running", json_object_new_boolean(running)); json_object_object_add(root, "output", json_object_new_string(content ? content : "")); if (!running) { json_object_object_add(root, "exit_status", json_object_new_int(exit_status)); } if (content && *content) { char *copy = strdup(content); char *saveptr; char *line = strtok_r(copy, "\n", &saveptr); while (line) { fprintf(stdout, "[%d]\t %s\n", pid, line); line = strtok_r(NULL, "\n", &saveptr); } fflush(stdout); free(copy); } char *out_str = strdup(json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); json_object_put(root); free(content); return out_str; } static char *python_terminate_execute(tool_t *self, struct json_object *args) { (void)self; struct json_object *pid_obj; if (!json_object_object_get_ex(args, "pid", &pid_obj)) return strdup("Error: missing 'pid'"); int pid = json_object_get_int(pid_obj); kill(pid, SIGTERM); usleep(100000); if (kill(pid, 0) == 0) kill(pid, SIGKILL); char log_path[256]; snprintf(log_path, sizeof(log_path), "/tmp/r_process_%d.log", pid); unlink(log_path); return strdup("Python process terminated and logs cleaned up."); } static struct json_object *python_execute_get_description(void) { struct json_object *root = json_object_new_object(); json_object_object_add(root, "type", json_object_new_string("function")); struct json_object *f = json_object_new_object(); json_object_object_add(f, "name", json_object_new_string("python_execute")); json_object_object_add(f, "description", json_object_new_string("Execute Python code. If async is true, returns PID immediately.")); struct json_object *p = json_object_new_object(); json_object_object_add(p, "type", json_object_new_string("object")); struct json_object *props = json_object_new_object(); struct json_object *src = json_object_new_object(); json_object_object_add(src, "type", json_object_new_string("string")); json_object_object_add(props, "source", src); struct json_object *to = json_object_new_object(); json_object_object_add(to, "type", json_object_new_string("integer")); json_object_object_add(props, "timeout", to); struct json_object *as = json_object_new_object(); json_object_object_add(as, "type", json_object_new_string("boolean")); json_object_object_add(props, "async", as); json_object_object_add(p, "properties", props); struct json_object *req = json_object_new_array(); json_object_array_add(req, json_object_new_string("source")); json_object_array_add(req, json_object_new_string("timeout")); json_object_array_add(req, json_object_new_string("async")); json_object_object_add(p, "required", req); json_object_object_add(p, "additionalProperties", json_object_new_boolean(0)); json_object_object_add(f, "parameters", p); r_config_handle cfg = r_config_get_instance(); if (r_config_use_strict(cfg)) json_object_object_add(f, "strict", json_object_new_boolean(1)); json_object_object_add(root, "function", f); return root; } static struct json_object *python_status_get_description(void) { struct json_object *root = json_object_new_object(); json_object_object_add(root, "type", json_object_new_string("function")); struct json_object *f = json_object_new_object(); json_object_object_add(f, "name", json_object_new_string("python_get_status")); json_object_object_add(f, "description", json_object_new_string("Get status and logs of a background Python process by PID.")); struct json_object *p = json_object_new_object(); json_object_object_add(p, "type", json_object_new_string("object")); struct json_object *props = json_object_new_object(); struct json_object *pid = json_object_new_object(); json_object_object_add(pid, "type", json_object_new_string("integer")); json_object_object_add(props, "pid", pid); json_object_object_add(p, "properties", props); struct json_object *req = json_object_new_array(); json_object_array_add(req, json_object_new_string("pid")); json_object_object_add(p, "required", req); json_object_object_add(p, "additionalProperties", json_object_new_boolean(0)); json_object_object_add(f, "parameters", p); r_config_handle cfg = r_config_get_instance(); if (r_config_use_strict(cfg)) json_object_object_add(f, "strict", json_object_new_boolean(1)); json_object_object_add(root, "function", f); return root; } static struct json_object *python_terminate_get_description(void) { struct json_object *root = json_object_new_object(); json_object_object_add(root, "type", json_object_new_string("function")); struct json_object *f = json_object_new_object(); json_object_object_add(f, "name", json_object_new_string("python_terminate")); json_object_object_add(f, "description", json_object_new_string("Terminate a background Python process and clean up.")); struct json_object *p = json_object_new_object(); json_object_object_add(p, "type", json_object_new_string("object")); struct json_object *props = json_object_new_object(); struct json_object *pid = json_object_new_object(); json_object_object_add(pid, "type", json_object_new_string("integer")); json_object_object_add(props, "pid", pid); json_object_object_add(p, "properties", props); struct json_object *req = json_object_new_array(); json_object_array_add(req, json_object_new_string("pid")); json_object_object_add(p, "required", req); json_object_object_add(p, "additionalProperties", json_object_new_boolean(0)); json_object_object_add(f, "parameters", p); r_config_handle cfg = r_config_get_instance(); if (r_config_use_strict(cfg)) json_object_object_add(f, "strict", json_object_new_boolean(1)); json_object_object_add(root, "function", f); return root; }