2025-03-03 08:32:41 +01:00
// Written by retoor@molodetz.nl
// This code defines functions for HTTP requests and structuring tool descriptions and executions in JSON format using the JSON-C library. It uses cURL for HTTP requests.
// Imports not part of the language itself: JSON-C (json-c/json.h, json-c/json_object.h) and a custom header "http_curl.h"
// MIT License
2025-03-03 08:07:17 +01:00
# ifndef R_TOOLS_H
# define R_TOOLS_H
# include <json-c/json.h>
# include <json-c/json_object.h>
# include <string.h>
# include "http_curl.h"
2025-03-03 13:51:57 +01:00
# include <dirent.h>
# include <sys/stat.h>
# include <time.h>
# include <glob.h>
2025-03-03 08:07:17 +01:00
2025-03-03 08:32:41 +01:00
struct json_object * tool_description_http_get ( ) ;
2025-03-03 13:51:57 +01:00
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 ( ) ;
2025-03-03 08:07:17 +01:00
2025-03-03 08:32:41 +01:00
struct json_object * tools_descriptions ( ) {
2025-03-03 08:07:17 +01:00
struct json_object * root = json_object_new_array ( ) ;
json_object_array_add ( root , tool_description_http_get ( ) ) ;
2025-03-03 13:51:57 +01:00
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 ( ) ) ;
2025-03-03 08:07:17 +01:00
return root ;
}
2025-03-03 08:32:41 +01:00
char * tool_function_http_get ( char * url ) {
2025-03-03 09:39:19 +01:00
fprintf ( stderr , " Tool http_get: %s \n " , url ) ;
2025-03-03 08:07:17 +01:00
return curl_get ( url ) ;
}
2025-03-03 13:51:57 +01:00
char * tool_function_linux_terminal ( char * command ) {
2025-03-03 09:39:19 +01:00
2025-03-03 13:51:57 +01:00
fprintf ( stderr , " Tool linux_terminal: %s \n " , command ) ;
2025-03-03 09:39:19 +01:00
FILE * fp ;
char buffer [ 1024 ] ;
size_t total_size = 0 ;
char * output = NULL ;
// Open the command for reading
fp = popen ( command , " r " ) ;
if ( fp = = NULL ) {
perror ( " popen failed " ) ;
2025-03-03 09:52:28 +01:00
return strdup ( " Popen failed! " ) ;
2025-03-03 09:39:19 +01:00
}
// Read output in chunks
while ( fgets ( buffer , sizeof ( buffer ) , fp ) ! = NULL ) {
size_t chunk_size = strlen ( buffer ) ;
char * new_output = realloc ( output , total_size + chunk_size + 1 ) ;
if ( new_output = = NULL ) {
perror ( " realloc failed " ) ;
free ( output ) ;
pclose ( fp ) ;
2025-03-03 09:52:28 +01:00
return strdup ( " Failed to allocate memory! " ) ;
2025-03-03 09:39:19 +01:00
}
output = new_output ;
strcpy ( output + total_size , buffer ) ;
total_size + = chunk_size ;
}
pclose ( fp ) ;
2025-03-03 13:51:57 +01:00
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 ;
2025-03-03 09:39:19 +01:00
}
2025-03-03 08:32:41 +01:00
struct json_object * tool_description_http_get ( ) {
2025-03-03 08:07:17 +01:00
struct json_object * root = json_object_new_object ( ) ;
json_object_object_add ( root , " type " , json_object_new_string ( " function " ) ) ;
2025-03-03 08:32:41 +01:00
2025-03-03 08:07:17 +01:00
struct json_object * function = json_object_new_object ( ) ;
json_object_object_add ( function , " name " , json_object_new_string ( " http_fetch " ) ) ;
2025-03-03 08:32:41 +01:00
json_object_object_add ( function , " description " , json_object_new_string ( " Get the contents of a URL. " ) ) ;
2025-03-03 08:07:17 +01:00
struct json_object * parameters = json_object_new_object ( ) ;
json_object_object_add ( parameters , " type " , json_object_new_string ( " object " ) ) ;
2025-03-03 08:32:41 +01:00
2025-03-03 08:07:17 +01:00
struct json_object * properties = json_object_new_object ( ) ;
struct json_object * url = json_object_new_object ( ) ;
json_object_object_add ( url , " type " , json_object_new_string ( " string " ) ) ;
2025-03-03 08:32:41 +01:00
json_object_object_add ( url , " description " , json_object_new_string ( " Fetch URL contents. " ) ) ;
2025-03-03 08:07:17 +01:00
json_object_object_add ( properties , " url " , url ) ;
2025-03-03 08:32:41 +01:00
2025-03-03 08:07:17 +01:00
json_object_object_add ( parameters , " properties " , properties ) ;
2025-03-03 08:32:41 +01:00
2025-03-03 08:07:17 +01:00
struct json_object * required = json_object_new_array ( ) ;
json_object_array_add ( required , json_object_new_string ( " url " ) ) ;
json_object_object_add ( parameters , " required " , required ) ;
2025-03-03 08:32:41 +01:00
2025-03-03 08:07:17 +01:00
json_object_object_add ( parameters , " additionalProperties " , json_object_new_boolean ( 0 ) ) ;
2025-03-03 08:32:41 +01:00
2025-03-03 08:07:17 +01:00
json_object_object_add ( function , " parameters " , parameters ) ;
json_object_object_add ( function , " strict " , json_object_new_boolean ( 1 ) ) ;
2025-03-03 08:32:41 +01:00
2025-03-03 08:07:17 +01:00
json_object_object_add ( root , " function " , function ) ;
2025-03-03 08:32:41 +01:00
2025-03-03 08:07:17 +01:00
return root ;
}
2025-03-03 13:51:57 +01:00
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 * function = json_object_new_object ( ) ;
json_object_object_add ( function , " name " , json_object_new_string ( " directory_glob " ) ) ;
2025-03-03 14:09:28 +01:00
json_object_object_add ( function , " description " , json_object_new_string ( " List the contents of a specified directory in glob format. "
2025-03-03 13:51:57 +01:00
" Result is a json array containing objects with keys: name, modification_date(iso), creation_date(iso), type and size_bytes. " ) ) ;
2025-03-03 09:39:19 +01:00
2025-03-03 13:51:57 +01:00
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 " ) ) ;
2025-03-03 14:09:28 +01:00
json_object_object_add ( directory , " description " , json_object_new_string ( " Path to the directory to list in glob format. " ) ) ;
2025-03-03 13:51:57 +01:00
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 ( ) {
2025-03-03 09:39:19 +01:00
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 ( ) ;
2025-03-03 13:51:57 +01:00
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. " ) ) ;
2025-03-03 09:39:19 +01:00
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 * url = json_object_new_object ( ) ;
json_object_object_add ( url , " type " , json_object_new_string ( " string " ) ) ;
json_object_object_add ( url , " description " , json_object_new_string ( " Bash command to execute. " ) ) ;
json_object_object_add ( properties , " command " , url ) ;
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 ;
}
2025-03-03 08:32:41 +01:00
struct json_object * tools_execute ( struct json_object * tools_array ) {
struct json_object * tools_result_messages = json_object_new_array ( ) ;
2025-03-03 08:07:17 +01:00
int array_len = json_object_array_length ( tools_array ) ;
2025-03-03 09:39:19 +01:00
2025-03-03 08:07:17 +01:00
for ( int i = 0 ; i < array_len ; i + + ) {
struct json_object * obj = json_object_array_get_idx ( tools_array , i ) ;
2025-03-03 08:32:41 +01:00
struct json_object * tool_result = json_object_new_object ( ) ;
2025-03-03 08:07:17 +01:00
2025-03-03 08:32:41 +01:00
json_object_object_add ( tool_result , " tool_call_id " ,
json_object_new_string ( json_object_get_string (
json_object_object_get ( obj , " id " ) ) ) ) ;
2025-03-03 08:07:17 +01:00
json_object_object_add ( tool_result , " role " , json_object_new_string ( " tool " ) ) ;
2025-03-03 08:32:41 +01:00
2025-03-03 08:07:17 +01:00
struct json_object * type_obj ;
if ( json_object_object_get_ex ( obj , " type " , & type_obj ) ) {
2025-03-03 08:32:41 +01:00
if ( strcmp ( json_object_get_string ( type_obj ) , " function " ) ) {
continue ;
}
2025-03-03 08:07:17 +01:00
}
2025-03-03 08:32:41 +01:00
2025-03-03 08:07:17 +01:00
struct json_object * function_obj ;
if ( json_object_object_get_ex ( obj , " function " , & function_obj ) ) {
struct json_object * name_obj ;
2025-03-03 08:32:41 +01:00
char * function_name = NULL ;
2025-03-03 08:07:17 +01:00
if ( json_object_object_get_ex ( function_obj , " name " , & name_obj ) ) {
function_name = ( char * ) json_object_get_string ( name_obj ) ;
}
2025-03-03 09:39:19 +01:00
2025-03-03 13:51:57 +01:00
if ( ! strcmp ( function_name , " linux_terminal_execute " ) ) {
2025-03-03 09:39:19 +01:00
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 ) ) {
2025-03-03 13:51:57 +01:00
char * command = ( char * ) json_object_get_string ( url_obj ) ;
char * http_result = tool_function_linux_terminal ( command ) ;
2025-03-03 09:39:19 +01:00
json_object_object_add ( tool_result , " content " , json_object_new_string ( http_result ) ) ;
}
}
}
2025-03-03 13:51:57 +01:00
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 ) ;
}
}
}
2025-03-03 08:32:41 +01:00
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 ) ) ;
struct json_object * url_obj ;
if ( json_object_object_get_ex ( arguments , " url " , & url_obj ) ) {
char * url = ( char * ) json_object_get_string ( url_obj ) ;
2025-03-03 09:39:19 +01:00
char * http_result = tool_function_http_get ( url ) ;
2025-03-03 08:32:41 +01:00
json_object_object_add ( tool_result , " content " , json_object_new_string ( http_result ) ) ;
}
2025-03-03 08:07:17 +01:00
}
}
2025-03-03 13:51:57 +01:00
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 ) ;
}
}
}
2025-03-03 08:07:17 +01:00
json_object_array_add ( tools_result_messages , tool_result ) ;
}
}
return tools_result_messages ;
}
2025-03-03 09:39:19 +01:00
# endif