diff --git a/main.c b/main.c index d5d9b02..cb85351 100644 --- a/main.c +++ b/main.c @@ -36,6 +36,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include "utils.h" bool SYNTAX_HIGHLIGHT_ENABLED = true; bool API_MODE = false; @@ -178,10 +179,14 @@ void render(char *content){ prompt[0] = 0; sprintf(prompt,"This are records seperated by newline: ```%s```. Respond to use with record that is about ```%s```. Rspond in plain text, do not execute command.",buffer, note_name); char* result = openai_chat("user",prompt); - printf("%s\n",result); - free(prompt); - free(result); + + free(buffer); + free(prompt); + if(result){ + printf("%s\n",result); + free(result); + } } if(!strcmp(parameter, "!write_note")){ @@ -303,9 +308,11 @@ void repl() { if(*line){ line_add_history(line); char *response = openai_chat("user", line); - render(response); - printf("\n"); - free(response); + if(response){ + render(response); + printf("\n"); + free(response); + } } } } @@ -377,7 +384,9 @@ bool openai_include(char *path) { " 8. find ten largest folders on my pc using sudo."); return true; } - FILE *file = fopen(path, "r"); + char * expanded_path = expand_home_directory(path); + FILE *file = fopen(expanded_path, "r"); + free(expanded_path); if (file == NULL) { return false; } diff --git a/messages.h b/messages.h index 8cbf423..cfe0808 100644 --- a/messages.h +++ b/messages.h @@ -25,6 +25,15 @@ struct json_object *message_list() { return message_array; } + +void messages_remove_last(){ + struct json_object *messages = message_list(); + int size = json_object_array_length(messages); + if(size){ + json_object_array_del_idx(messages, size - 1,1); + } +} + struct json_object *message_add_tool_call(struct json_object *message) { struct json_object *messages = message_list(); json_object_array_add(messages, message); @@ -67,4 +76,4 @@ void message_free() { } } -#endif \ No newline at end of file +#endif diff --git a/openai.h b/openai.h index fbf2b61..a0d517a 100644 --- a/openai.h +++ b/openai.h @@ -52,32 +52,39 @@ struct json_object* openai_process_chat_message(const char* api_url, const char* struct json_object* parsed_json = json_tokener_parse(response); if (!parsed_json) { fprintf(stderr, "Failed to parse JSON.\n %s \n", response); - return json_object_new_null(); + return NULL; } struct json_object *error_object; if (json_object_object_get_ex(parsed_json, "error", &error_object)) { fprintf(stderr, "Failed to get 'error' object.\n %s \n", response); json_object_put(parsed_json); - return json_object_new_null(); + char * all_messages = (char *)json_object_to_json_string(message_array); + fprintf(stderr, "Messages: "); + fwrite(all_messages,strlen(all_messages),1, stderr); + fprintf(stderr, "\n"); + free(all_messages); + messages_remove_last(); + messages_remove_last(); + return NULL; } struct json_object* choices_array; if (!json_object_object_get_ex(parsed_json, "choices", &choices_array)) { fprintf(stderr, "Failed to get 'choices' array.\n %s \n", response); json_object_put(parsed_json); - return json_object_new_null(); + return NULL; } struct json_object* first_choice = json_object_array_get_idx(choices_array, 0); if (!first_choice) { fprintf(stderr, "Failed to get the first element of 'choices'.\n"); json_object_put(parsed_json); - return json_object_new_null(); + return NULL; } struct json_object* message_object; if (!json_object_object_get_ex(first_choice, "message", &message_object)) { fprintf(stderr, "Failed to get 'message' object.\n"); json_object_put(parsed_json); - return json_object_new_null(); + return NULL; } return message_object; } @@ -86,6 +93,10 @@ char* openai_chat(const char* user_role, const char* message_content) { const char* api_url = "https://api.openai.com/v1/chat/completions"; char* json_data = chat_json(user_role, message_content); struct json_object* message_object = openai_process_chat_message(api_url, json_data); + if(message_object == NULL) { + printf("ERROR + NULL IS SUCCESS\n"); + return NULL; + } struct json_object* tool_calls; json_object_object_get_ex(message_object, "tool_calls", &tool_calls); if (tool_calls) { @@ -98,6 +109,9 @@ char* openai_chat(const char* user_role, const char* message_content) { } char* tool_calls_result_str = chat_json(NULL, NULL); message_object = openai_process_chat_message(api_url, tool_calls_result_str); + if(message_object == NULL) { + return NULL; + } message_add_tool_call(message_object); } const char* content_str = json_object_get_string(json_object_object_get(message_object, "content")); diff --git a/tools.h b/tools.h index ae9b895..0e41b8c 100644 --- a/tools.h +++ b/tools.h @@ -24,6 +24,7 @@ struct json_object *tool_description_directory_glob(); struct json_object *tool_description_read_file(); struct json_object *tool_description_write_file(); struct json_object *tool_description_directory_rglob(); +struct json_object *tool_description_linux_terminal_interactive(); struct json_object *tools_descriptions() { struct json_object *root = json_object_new_array(); @@ -33,7 +34,7 @@ struct json_object *tools_descriptions() { json_object_array_add(root, tool_description_read_file()); json_object_array_add(root, tool_description_write_file()); json_object_array_add(root, tool_description_directory_rglob()); - + json_object_array_add(root, tool_description_linux_terminal_interactive()); return root; } @@ -57,7 +58,7 @@ char *tool_function_linux_terminal(char *command) { while (fgets(buffer, sizeof(buffer), fp) != NULL) { size_t chunk_size = strlen(buffer); - char *new_output = realloc(output, total_size + chunk_size + 1); + char *new_output = (char *)realloc(output, total_size + chunk_size + 1); if (new_output == NULL) { perror("realloc failed"); free(output); @@ -73,6 +74,54 @@ char *tool_function_linux_terminal(char *command) { return output ? output : strdup(""); } +char *tool_function_linux_terminal_interactive(char *command) { + fprintf(stderr, "Tool linux_terminal_interactive: %s\n", command); + + int result_code = system(command); + + char * result = (char *)malloc(100); + result[0] = 0; + sprintf(result, "Command exited with status code %d.", result_code); + + return result; +} + +struct json_object *tool_description_linux_terminal_interactive() { + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); + + struct json_object *function = json_object_new_object(); + json_object_object_add(function, "name", json_object_new_string("linux_terminal_execute_interactive")); + json_object_object_add(function, "description", json_object_new_string("Executes interactive terminal for user. You will not be able to read the result. Do not use if you need to know output.")); + + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); + + struct json_object *properties = json_object_new_object(); + struct json_object *path = json_object_new_object(); + json_object_object_add(path, "type", json_object_new_string("string")); + json_object_object_add(path, "description", json_object_new_string("Executable with parameters to execute interactive."));; + json_object_object_add(properties, "command", path); + + json_object_object_add(parameters, "properties", properties); + + struct json_object *required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("command")); + json_object_object_add(parameters, "required", required); + + json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0)); + + json_object_object_add(function, "parameters", parameters); + json_object_object_add(function, "strict", json_object_new_boolean(1)); + + json_object_object_add(root, "function", function); + + return root; +} + + + + struct json_object *tool_description_directory_rglob() { struct json_object *root = json_object_new_object(); json_object_object_add(root, "type", json_object_new_string("function")); @@ -537,12 +586,24 @@ struct json_object *tools_execute(struct json_object *tools_array) { struct json_object *url_obj; if (json_object_object_get_ex(arguments, "command", &url_obj)) { char *command = (char *)json_object_get_string(url_obj); - char *http_result = tool_function_linux_terminal(command); - json_object_object_add(tool_result, "content", json_object_new_string(http_result)); + char *terminal_result = tool_function_linux_terminal(command); + json_object_object_add(tool_result, "content", json_object_new_string(terminal_result)); + free(terminal_result); } } - } - if (!strcmp(function_name, "directory_glob")) { + } else if (!strcmp(function_name, "linux_terminal_execute_interactive")) { + struct json_object *arguments_obj; + if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { + struct json_object *arguments = json_tokener_parse(json_object_get_string(arguments_obj)); + struct json_object *url_obj; + if (json_object_object_get_ex(arguments, "command", &url_obj)) { + char *command = (char *)json_object_get_string(url_obj); + char *terminal_result = tool_function_linux_terminal_interactive(command); + json_object_object_add(tool_result, "content", json_object_new_string(terminal_result)); + free(terminal_result); + } + } + }else if (!strcmp(function_name, "directory_glob")) { struct json_object *arguments_obj; if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { struct json_object *arguments = json_tokener_parse(json_object_get_string(arguments_obj)); @@ -554,8 +615,7 @@ struct json_object *tools_execute(struct json_object *tools_array) { free(listing_result); } } - } - if (!strcmp(function_name, "http_fetch")) { + } else if (!strcmp(function_name, "http_fetch")) { struct json_object *arguments_obj; if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { struct json_object *arguments = json_tokener_parse(json_object_get_string(arguments_obj)); @@ -564,11 +624,10 @@ struct json_object *tools_execute(struct json_object *tools_array) { char *url = (char *)json_object_get_string(url_obj); char *http_result = tool_function_http_get(url); json_object_object_add(tool_result, "content", json_object_new_string(http_result)); + free(http_result); } } - } - - if (!strcmp(function_name, "read_file")) { + } else if (!strcmp(function_name, "read_file")) { struct json_object *arguments_obj; if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { struct json_object *path_obj; @@ -582,8 +641,7 @@ struct json_object *tools_execute(struct json_object *tools_array) { free(file_content); } } - } - if (!strcmp(function_name, "write_file")) { + } else if (!strcmp(function_name, "write_file")) { struct json_object *arguments_obj; if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { struct json_object *path_obj, *content_obj; @@ -599,8 +657,7 @@ struct json_object *tools_execute(struct json_object *tools_array) { free(write_result); } } - } - if (!strcmp(function_name, "directory_rglob")) { + } else if (!strcmp(function_name, "directory_rglob")) { struct json_object *arguments_obj; if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { struct json_object *arguments = json_tokener_parse(json_object_get_string(arguments_obj)); @@ -612,6 +669,9 @@ struct json_object *tools_execute(struct json_object *tools_array) { free(listing_result); } } + }else { + fprintf(stderr, "Unkown function: %s\n", function_name); + json_object_object_add(tool_result, "content", json_object_new_string("Error: function not found.")); } json_object_array_add(tools_result_messages, tool_result);