Working version.

This commit is contained in:
retoor 2025-03-03 13:51:57 +01:00
parent d26013a90f
commit 0807b91dd6
3 changed files with 330 additions and 40 deletions

4
chat.h
View File

@ -42,7 +42,7 @@ char *prompt_model = "gpt-3.5-turbo";
char *prompt_model = "gpt-4o-mini";
#endif
int prompt_max_tokens = 2048;
double prompt_temperature = 0.5;
double prompt_temperature = 0.1;
json_object *_prompt = NULL;
@ -72,6 +72,8 @@ char *chat_json(char *role, char *message) {
json_object_object_add(root_object, "max_tokens", json_object_new_int(prompt_max_tokens));
json_object_object_add(root_object, "temperature", json_object_new_double(prompt_temperature));
printf("%s\n", json_object_to_json_string_ext(root_object, JSON_C_TO_STRING_PRETTY));
return (char *)json_object_to_json_string_ext(root_object, JSON_C_TO_STRING_PRETTY);
}

View File

@ -6,7 +6,6 @@
// MIT License: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files, to deal in the Software without restriction, including the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef R_OPENAI_H
#define R_OPENAI_H
#include "http.h"
@ -15,70 +14,83 @@
#include <string.h>
#include <stdbool.h>
char* openai_get_models() {
char* url = "https://api.openai.com/v1/models";
return https_get(url);
char* openai_fetch_models() {
char* api_url = "https://api.openai.com/v1/models";
return https_get(api_url);
}
bool openai_system(char* content) {
char* url = "https://api.openai.com/v1/chat/completions";
char* data = chat_json("system", content);
char* result = curl_post(url, data);
bool is_done = result != NULL;
free(result);
return is_done;
bool openai_system(char* message_content) {
//char* api_url = "https://api.openai.com/v1/chat/completions";
(void)chat_json("system", message_content);
//if (!json_data) {
// fprintf(stderr, "Failed to create JSON data.\n");
// return false;
//}
//char* response = curl_post(api_url, json_data);
//free(json_data); // Free the data after use
//bool is_successful = response != NULL;
//free(response);
return true; //is_successful;
}
struct json_object* chat_message(char* url, char* data) {
char* result = curl_post(url, data);
struct json_object* parsed_json = json_tokener_parse(result);
struct json_object* openai_process_chat_message(char* api_url, char* json_data) {
char* response = curl_post(api_url, json_data);
struct json_object* parsed_json = json_tokener_parse(response);
if (!parsed_json) {
fprintf(stderr, "Failed to parse JSON.\n");
fprintf(stderr, "%s\n", result);
return NULL;
fprintf(stderr, "%s\n", response);
return json_object_new_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");
fprintf(stderr, "%s\n", response);
json_object_put(parsed_json);
return json_object_new_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");
fprintf(stderr, "%s\n", result);
fprintf(stderr, "%s\n", response);
json_object_put(parsed_json);
return NULL;
return json_object_new_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 NULL;
return json_object_new_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 NULL;
return json_object_new_null();
}
return message_object;
}
char* openai_chat(char* role, char* content) {
char* url = "https://api.openai.com/v1/chat/completions";
char* data = chat_json(role, content);
json_object* message_object = chat_message(url, data);
char* openai_chat(char* user_role, char* message_content) {
char* api_url = "https://api.openai.com/v1/chat/completions";
char* json_data = chat_json(user_role, message_content);
json_object* message_object = openai_process_chat_message(api_url, json_data);
struct json_object* tool_calls;
json_object_object_get_ex(message_object, "tool_calls", &tool_calls);
if (tool_calls) {
message_add_tool_call(message_object);
json_object* tool_call_results = tools_execute(tool_calls);
int array_len = json_object_array_length(tool_call_results);
for (int i = 0; i < array_len; i++) {
int results_count = json_object_array_length(tool_call_results);
for (int i = 0; i < results_count; i++) {
json_object* tool_call_result = json_object_array_get_idx(tool_call_results, i);
message_add_tool_call(tool_call_result);
}
char* tool_calls_result_str = chat_json(NULL, NULL);
message_object = chat_message(url, tool_calls_result_str);
message_object = openai_process_chat_message(api_url, tool_calls_result_str);
message_add_tool_call(message_object);
}
char* content_str = (char*)json_object_get_string(json_object_object_get(message_object, "content"));
return strdup(content_str);
}
#endif
#endif

298
tools.h
View File

@ -13,14 +13,28 @@
#include <json-c/json_object.h>
#include <string.h>
#include "http_curl.h"
#include <dirent.h>
#include <sys/stat.h>
#include <time.h>
#include <glob.h>
struct json_object *tool_description_http_get();
struct json_object *tool_description_bash();
struct json_object *tool_description_linux_terminal();
struct json_object *tool_description_directory_glob();
struct json_object *tool_description_read_file();
struct json_object *tool_description_write_file();
struct json_object *tools_descriptions() {
struct json_object *root = json_object_new_array();
json_object_array_add(root, tool_description_http_get());
json_object_array_add(root, tool_description_bash());
json_object_array_add(root, tool_description_linux_terminal());
json_object_array_add(root, tool_description_directory_glob());
json_object_array_add(root, tool_description_read_file());
json_object_array_add(root, tool_description_write_file());
char * result = strdup(json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY));
printf("%s\n", result);
return root;
}
@ -29,9 +43,9 @@ char *tool_function_http_get(char *url) {
return curl_get(url);
}
char * tool_function_bash(char * command){
char * tool_function_linux_terminal(char * command){
fprintf(stderr, "Tool bash: %s\n", command);
fprintf(stderr, "Tool linux_terminal: %s\n", command);
FILE *fp;
char buffer[1024];
size_t total_size = 0;
@ -60,7 +74,190 @@ char * tool_function_bash(char * command){
}
pclose(fp);
return output;
return output ? output : strdup("");
}
struct json_object *tool_description_read_file() {
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("read_file"));
json_object_object_add(function, "description", json_object_new_string("Reads / opens / loads a file and returns its contents as a string."));
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("Path to the file to read / open / load."));
json_object_object_add(properties, "path", 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("path"));
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;
}
// Write File Description
struct json_object *tool_description_write_file() {
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("write_file"));
json_object_object_add(function, "description", json_object_new_string("Writes / saves / stores content to a file."));
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("Path to the file to write / save / store."));
json_object_object_add(properties, "path", path);
struct json_object *content = json_object_new_object();
json_object_object_add(content, "type", json_object_new_string("string"));
json_object_object_add(content, "description", json_object_new_string("Content to write / save / store into the file."));
json_object_object_add(properties, "content", content);
json_object_object_add(parameters, "properties", properties);
struct json_object *required = json_object_new_array();
json_object_array_add(required, json_object_new_string("path"));
json_object_array_add(required, json_object_new_string("content"));
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;
}
char *tool_function_read_file(char *path) {
fprintf(stderr, "Tools read_file: %s\n", path);
FILE *fp = fopen(path, "r");
if (fp == NULL) {
perror("fopen failed");
return strdup("Failed to open file for reading!");
}
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
rewind(fp);
char *content = (char *)malloc(size + 1);
if (content == NULL) {
fclose(fp);
return strdup("Memory allocation failed!");
}
ssize_t read_size = fread(content, 1, size, fp);
(void)read_size;
content[size] = '\0';
fclose(fp);
return content;
}
// Write content to a file
char *tool_function_write_file(char *path, char *content) {
fprintf(stderr, "Tools write_file with %zu bytes: %s\n", strlen(content), path);
FILE *fp = fopen(path, "w");
if (fp == NULL) {
perror("fopen failed");
return strdup("Failed to open file for writing!");
}
fwrite(content, 1, strlen(content), fp);
fclose(fp);
return strdup("File written successfully.");
}
const char *get_file_type(struct stat *st) {
if (S_ISREG(st->st_mode)) return "file";
if (S_ISDIR(st->st_mode)) return "directory";
return "other";
}
// Function to convert timestamp to human-readable format
void format_time(time_t raw_time, char *buffer, size_t size) {
struct tm *time_info = localtime(&raw_time);
strftime(buffer, size, "%Y-%m-%d %H:%M:%S", time_info);
}
char * tool_function_directory_glob(char *target_dir) {
fprintf(stderr, "Tools directory_glob: %s\n", target_dir);
glob_t results;
struct stat file_stat;
char mod_time[20], create_time[20];
if(!strcmp(target_dir, ".")) {
target_dir[0] = '*';
}
// Perform glob search
if (glob(target_dir, GLOB_TILDE, NULL, &results) != 0) {
perror("glob failed");
return NULL;
}
// Create a JSON array to store results
json_object *json_array = json_object_new_array();
// Iterate through the matched files
for (size_t i = 0; i < results.gl_pathc; i++) {
const char *file_path = results.gl_pathv[i];
// Get file stats
if (stat(file_path, &file_stat) == -1) {
perror("stat failed");
continue;
}
// Format timestamps
format_time(file_stat.st_mtime, mod_time, sizeof(mod_time));
format_time(file_stat.st_ctime, create_time, sizeof(create_time)); // Creation time is unreliable on Linux
// Create JSON object for each file
json_object *json_entry = json_object_new_object();
json_object_object_add(json_entry, "name", json_object_new_string(file_path));
json_object_object_add(json_entry, "modification_date", json_object_new_string(mod_time));
json_object_object_add(json_entry, "creation_date", json_object_new_string(create_time));
json_object_object_add(json_entry, "type", json_object_new_string(get_file_type(&file_stat)));
json_object_object_add(json_entry, "size_bytes", json_object_new_int64(file_stat.st_size));
// Add to JSON array
json_object_array_add(json_array, json_entry);
}
// Free glob results
globfree(&results);
char * result = strdup(json_object_to_json_string_ext(json_array, JSON_C_TO_STRING_PRETTY));
// Cleanup
json_object_put(json_array);
return result;
}
struct json_object *tool_description_http_get() {
@ -96,14 +293,47 @@ struct json_object *tool_description_http_get() {
return root;
}
struct json_object *tool_description_directory_glob() {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
struct json_object *tool_description_bash() {
struct json_object *function = json_object_new_object();
json_object_object_add(function, "name", json_object_new_string("directory_glob"));
json_object_object_add(function, "description", json_object_new_string("List the contents of a specified directory. "
"Result is a json array containing objects with keys: name, modification_date(iso), creation_date(iso), type and size_bytes."));
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 *directory = json_object_new_object();
json_object_object_add(directory, "type", json_object_new_string("string"));
json_object_object_add(directory, "description", json_object_new_string("Path to the directory to list."));
json_object_object_add(properties, "path", directory);
json_object_object_add(parameters, "properties", properties);
struct json_object *required = json_object_new_array();
json_object_array_add(required, json_object_new_string("path"));
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_linux_terminal() {
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("bash_execute"));
json_object_object_add(function, "description", json_object_new_string("Execute a bash command on user terminal."));
json_object_object_add(function, "name", json_object_new_string("linux_terminal_execute"));
json_object_object_add(function, "description", json_object_new_string("Execute a linux_terminal command on user terminal."));
struct json_object *parameters = json_object_new_object();
json_object_object_add(parameters, "type", json_object_new_string("object"));
@ -159,18 +389,31 @@ struct json_object *tools_execute(struct json_object *tools_array) {
function_name = (char *)json_object_get_string(name_obj);
}
if (!strcmp(function_name, "bash_execute")) {
if (!strcmp(function_name, "linux_terminal_execute")) {
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 *url = (char *)json_object_get_string(url_obj);
char *http_result = tool_function_bash(url);
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));
}
}
}
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));
struct json_object *path_obj;
if (json_object_object_get_ex(arguments, "path", &path_obj)) {
char *path = (char *)json_object_get_string(path_obj);
char *listing_result = tool_function_directory_glob(path);
json_object_object_add(tool_result, "content", json_object_new_string(listing_result));
free(listing_result);
}
}
}
if (!strcmp(function_name, "http_fetch")) {
struct json_object *arguments_obj;
if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) {
@ -183,6 +426,39 @@ struct json_object *tools_execute(struct json_object *tools_array) {
}
}
}
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;
struct json_object *arguments = json_tokener_parse(json_object_get_string(arguments_obj));
if (json_object_object_get_ex(arguments, "path", &path_obj)) {
char *path = (char *)json_object_get_string(path_obj);
char *file_content = tool_function_read_file(path);
json_object_object_add(tool_result, "content", json_object_new_string(file_content));
free(file_content);
}
}
}
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;
struct json_object *arguments = json_tokener_parse(json_object_get_string(arguments_obj));
if (json_object_object_get_ex(arguments, "path", &path_obj) &&
json_object_object_get_ex(arguments, "content", &content_obj)) {
char *path = (char *)json_object_get_string(path_obj);
char *content = (char *)json_object_get_string(content_obj);
char *write_result = tool_function_write_file(path, content);
json_object_object_add(tool_result, "content", json_object_new_string(write_result));
free(write_result);
}
}
}
json_object_array_add(tools_result_messages, tool_result);
}
}