This commit is contained in:
retoor 2025-03-03 14:51:13 +01:00
parent 2f8701fef3
commit bee172c6eb

219
tools.h
View File

@ -23,6 +23,8 @@ 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 *tool_description_directory_rglob();
struct json_object *tools_descriptions() {
struct json_object *root = json_object_new_array();
@ -31,7 +33,7 @@ struct json_object *tools_descriptions() {
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());
json_object_array_add(root, tool_description_directory_rglob());
return root;
}
@ -75,6 +77,42 @@ char * tool_function_linux_terminal(char * command){
return output ? output : strdup("");
}
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"));
struct json_object *function = json_object_new_object();
json_object_object_add(function, "name", json_object_new_string("directory_rglob"));
json_object_object_add(function, "description", json_object_new_string("Recursively list the contents of a specified directory in glob format. "
"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 in glob format."));
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_read_file() {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
@ -203,6 +241,171 @@ void format_time(time_t raw_time, char *buffer, size_t size) {
strftime(buffer, size, "%Y-%m-%d %H:%M:%S", time_info);
}
void recursive_glob(const char *pattern, glob_t *results) {
// First, find all matching files in the current scope
glob_t current_matches;
int ret = glob(pattern, GLOB_NOSORT | GLOB_TILDE, NULL, &current_matches);
// Handle errors
if (ret != 0 && ret != GLOB_NOMATCH) {
// Copy error state to results
results->gl_pathc = 0;
results->gl_pathv = NULL;
results->gl_offs = 0;
return;
}
// Initialize results if this is the first call
if (results->gl_pathv == NULL) {
memset(results, 0, sizeof(glob_t));
}
// Add found paths to results
for (size_t i = 0; i < current_matches.gl_pathc; i++) {
char *path = current_matches.gl_pathv[i];
// Add the path to results
if (results->gl_pathc == 0) {
// First result
results->gl_pathc = 1;
results->gl_pathv = malloc(sizeof(char *));
results->gl_pathv[0] = strdup(path);
} else {
// Additional result
results->gl_pathc++;
results->gl_pathv = realloc(results->gl_pathv,
results->gl_pathc * sizeof(char *));
results->gl_pathv[results->gl_pathc - 1] = strdup(path);
}
}
// Now look for directories to recurse into
DIR *dir;
struct dirent *entry;
struct stat statbuf;
// Extract directory part from pattern
char *pattern_copy = strdup(pattern);
char *last_slash = strrchr(pattern_copy, '/');
char *dir_path;
char *file_pattern;
if (last_slash) {
*last_slash = '\0';
dir_path = pattern_copy;
file_pattern = last_slash + 1;
} else {
// No directory part in the pattern
dir_path = ".";
file_pattern = pattern_copy;
}
if ((dir = opendir(dir_path)) != NULL) {
while ((entry = readdir(dir)) != NULL) {
// Skip . and ..
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
// Construct full path - ensure sufficient buffer space
char full_path[PATH_MAX];
int path_len;
if (strcmp(dir_path, ".") == 0) {
path_len = snprintf(full_path, PATH_MAX, "%s", entry->d_name);
} else {
path_len = snprintf(full_path, PATH_MAX, "%s/%s", dir_path, entry->d_name);
}
// Check if snprintf truncated the output
if (path_len >= PATH_MAX) {
// Path too long, skip this entry
continue;
}
// Check if it's a directory
if (stat(full_path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
// Create new pattern for recursion - ensure sufficient buffer space
char new_pattern[PATH_MAX];
int new_pattern_len = snprintf(new_pattern, PATH_MAX, "%s/%s", full_path, file_pattern);
// Check if snprintf truncated the output
if (new_pattern_len >= PATH_MAX) {
// Pattern too long, skip this recursion
continue;
}
// Recurse
recursive_glob(new_pattern, results);
}
}
closedir(dir);
}
// Free temporary resources
free(pattern_copy);
globfree(&current_matches);
}
char *tool_function_directory_rglob(char *target_dir) {
fprintf(stderr, "Tools directory_rglob: %s\n", target_dir);
glob_t results;
results.gl_pathc = 0;
struct stat file_stat;
char mod_time[20], create_time[20];
// Perform glob search recursively
recursive_glob(target_dir, &results);
// 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;
}
char * tool_function_directory_glob(char *target_dir) {
fprintf(stderr, "Tools directory_glob: %s\n", target_dir);
glob_t results;
@ -457,6 +660,20 @@ struct json_object *tools_execute(struct json_object *tools_array) {
}
}
}
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));
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_rglob(path);
json_object_object_add(tool_result, "content", json_object_new_string(listing_result));
free(listing_result);
}
}
}
json_object_array_add(tools_result_messages, tool_result);
}
}