// retoor <retoor@molodetz.nl>
#include "tool.h"
#include "r_config.h"
#include "bash_executor.h"
#include "markdown.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
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 const tool_vtable_t python_execute_vtable = {
.get_description = python_execute_get_description,
.execute = python_execute_execute,
.print_action = python_execute_print_action
};
static tool_t python_execute_tool = { .vtable = &python_execute_vtable, .name = "python_execute" };
tool_t *tool_python_execute_create(void) { return &python_execute_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));
json_object_object_add(root, "auto_backgrounded", 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 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;
}