From 04785fe35017d32104b003d1e5147b7887da0cf3 Mon Sep 17 00:00:00 2001 From: retoor <retoor@molodetz.nl> Date: Sat, 22 Mar 2025 03:15:49 +0100 Subject: [PATCH] Update. --- .r_history | 470 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Makefile | 4 +- browse.c | 15 ++ browse.h | 41 +++++ cmd.sh | 37 +++++ database.db | Bin 0 -> 24576 bytes db_utils.c | 59 +++++++ db_utils.h | 141 ++++++++++++++++ indexer.h | 133 +++++++++++++++ main.c | 10 +- openai.h | 11 +- r.h | 8 + rpylib.so | Bin 0 -> 76312 bytes script.sh | 9 + setup.py | 10 ++ tools.h | 393 +++++++++++++++++++++++++++++++++++++++++-- 16 files changed, 1323 insertions(+), 18 deletions(-) create mode 100644 .r_history create mode 100644 browse.c create mode 100644 browse.h create mode 100644 cmd.sh create mode 100644 database.db create mode 100644 db_utils.c create mode 100644 db_utils.h create mode 100644 indexer.h create mode 100644 r.h create mode 100755 rpylib.so create mode 100644 script.sh create mode 100644 setup.py diff --git a/.r_history b/.r_history new file mode 100644 index 0000000..f91a1bc --- /dev/null +++ b/.r_history @@ -0,0 +1,470 @@ +htop +How much bigger is my disk than my memory? +fetch my ten bytes from /dev/urandom +ddos https://molodetz.nl +do ab benchmark on https://molodetz.nl +do ab benchmark on https://molodetz.nl with -c 10 -n 1000 +validate computer security +r check system security +does https://blog.nldr.net/ contain a typo? +any more? +does https://molodetz.nl contain a typo? +r how much times is my disk bigger than my memory? How much would it kinda cost to upgrade my memory so much that it will match my disk side? +generate a python script that prints "Lekker voor je!". Save it to lekker.py. execute it with python3. +execute +Hi +What model are you? +What eversion of the model? +what is iotop-c package? +What is the difference between iotop-c and iotop? +execute iotop +sudo iptop +json-c to string in c +does fprintf have a limit? +what is better to use than fprintf when writing much data. +How to do fwrite +how to pretty print json-c string +json-c remove last element from json array +asasfqgwq +execute interactive iotop +sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) attempt to write a readonly database +What points are not very valid from https://devrant.com/rants/13665478/at12bitfloat-serious-debate-on-rust-vs-c-here-are-my-arguments-c-has-1-better-sy +What points are just plain wrong from https://devrant.com/rants/13665478/at12bitfloat-serious-debate-on-rust-vs-c-here-are-my-arguments-c-has-1-better-sy +Grade every statement from 1-10 regarding https://devrant.com/rants/13665478/at12bitfloat-serious-debate-on-rust-vs-c-here-are-my-arguments-c-has-1-better-sy +find out where my disk space goes to +I want a c websocket client that can send text +Does windows have a shortcut to open a terminal? +Hi +Why +hi +How much mb is 134217728 bytes +hi +hi +list all files +check if my pc has rust +create a ne wrust project and add cli libs +do it +run it +execute the binary result +do it +run the binary +do a cargo run porjecct +Bash traps how do they work and how can i let it repeat last command? +HOw to make a backup command iwth tiemstamp file name in a make file command +list files in current directory. +read x.txt write xy.txt say haha +read x.txt write xy.txt say haha and finally send DONE! +read x.txt write xy.txt say haha and finally send DONE! +read x.txt write xy.txt say haha and finally send DONE! +continue +continue +How to uncomment vim +There must be a shortcut +What would you say what hte level is of this developer?? http://localhost:8082/ +What could be better about the site?? +what book +what is the exiting year? +what about 1984? +what are you fan of? +Who are you? +list files +ls +cat all text files +cat all text files +cat all text files +cat all text files +Who are you? +how to run ftpd +How to run the normal ftpd on linux +How does ollama tools api work using http? +How to do class based views in aiohttp +How to access app from clas based view +How to do have url tail in aiohttp server route +Show how to use sqlite in python +make sqlite3 cursor select query return dicts +Generate rust source code that shows a message in the right upper corner of the screen. +Not of terminal, but on desktop +do all this for me +continue +It says | ^^^^^^^^^^^^^^^^^^^^^^^^^ no `native_windows_gui` in the root +do it +do it +remove this project +create a rust websocket client project that sends this json to https://snek.molodetz.nl/rpc.ws: {"method":"login","args":["username","password"]} +do it +error[E0599]: no method named `send` found for struct `WebSocketStream` in the current scope + --> src/main.rs:19:15 + | +19 | ws_stream.send(Message::Text(json_message.to_string())).await.expec... + | ^^^^ + | + ::: /home/retoor/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-util-0.3.31/src/sink/mod.rs +do it +error[E0433]: failed to resolve: use of undeclared crate or module `futures_util` + --> src/main.rs:8:5 + | +8 | use futures_util::sink::SinkExt; + | ^^^^^^^^^^^^ use of undeclared crate or module `futures_util` +error[E0599]: no method named `send` found for struct `WebSocketStream` in the current scope + --> src/main.rs:20:15 + | +do it +replace url with wss://snek.molodetz.nl/rpc.ws +do it +Failed to connect: Url(TlsFeatureNotEnabled) +do it +error: failed to select a version for `tokio-tungstenite`. + ... required by package `websocket_client v0.1.0 (/home/retoor/websocket_client)` +versions that meet the requirements `^0.17` (locked to 0.17.2) are: 0.17.2 +do it +error: failed to select a version for `tokio-tungstenite`. + ... required by package `websocket_client v0.1.0 (/home/retoor/websocket_client)` +versions that meet the requirements `^0.17` (locked to 0.17.2) are: 0.17.2 +the package `websocket_client` depends on `tokio-tungstenite`, with features: `tls` but `tokio-tungstenite` does not have these features. +do it +error: failed to select a version for `tokio-tungstenite`. + ... required by package `websocket_client v0.1.0 (/home/retoor/websocket_client)` +versions that meet the requirements `^0.15` are: 0.15.0 +the package `websocket_client` depends on `tokio-tungstenite`, with features: `tls` but `tokio-tungstenite` does not have these features. +failed to select a version for `tokio-tungstenite` which could resolve this conflict +do it +thread 'main' panicked at src/main.rs:13:55: +Failed to connect: Url(TlsFeatureNotEnabled) +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +do it +do it +do it +do it +do it +thread 'main' panicked at src/main.rs:13:55: +Failed to connect: Url(TlsFeatureNotEnabled) +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +do it +do it +do it +create a C# project that does the same things as the rust project you've just generated +do it +do it +do it +do it +do it +do it +do it +upgrade the project to dotnet 9.0 +do it +do it +Unhandled exception. System.PlatformNotSupportedException: Operation is not supported on this platform. + at System.Func`3.BeginInvoke(T1 arg1, T2 arg2, AsyncCallback callback, Object object) + at WebSocketSharp.WebSocket.send(Opcode opcode, Byte[] data, Action`1 completed) + at WebSocketSharp.WebSocket.Send(String data, Action`1 completed) + at WebSocketSharp.WebSocket.Send(String data) + at Program.Main(String[] args) in /home/retoor/WebSocketClient/Program.cs:line 23 +do it +do it +Make it listen for response message afterwards and display it. +do it +replace username with retoor and password with retoorded +do it +make it receive messages within a loon instead of once. +make run +If c application says 'core dumped' where is it dumped? +Why +do it +htop +Helping someone with his phone always comes with danger. +I just touched someones phone and his screen went black. +The guy was directly like 'What did you do?' omg. +asfafs +Haaah +index +index +r +r +index +index +investigate +investigate +investigate +investigate +ls *.cs +read file +Do you see any optimizations? +list *.c +list *.cs +read +read that file +what can be optimized? +Apply optimizations +make run +index +make it auto reconnecting after error / connection lost. +yes + make run +index +format Program.cs +yes +make linux +I think there were warnings. +yes +How doe a javascript sum +jinja number format 1000's dot +python number format +build project +yes +repair the build +ok +wait +investigate +do build but add 2>&1 +do it +yes +rlob * +make project +do it +yes +yes +yes +make -f build/Makefile 2>&1 +yes +yes +yes +minimal docker file that i can use to compile c++ programs with cmake +index +merge print_json_output into index_directory and make index_directory thus return a string +y +Remove MAX_EXTENSIONS. There must be better solution +y +read tools.h +Add a new tool named 'index_directory' with 'path' as parameter. +yes +read tools.h +Add a new tool named 'index_directory' with 'path' as parameter. +Update the original source with that source. +read tools.h +I want to add a new tool to tools.h +The function should be named index_director, description has to be "Index directory recursively and read all source files and list them.", parameters: path<string>,return list +yes +model +ls +bash: cannot set terminal process group (78989): Inappropriate ioctl for device python subprocess +This is source code:```import asyncio +import aiohttp +import aiohttp.web +import os +import pty +import shlex +import subprocess +import pathlib +class TerminalSession: + def __init__(self,command): + self.command = command + self.master, self.slave = pty.openpty() # Create pseudo-terminal + self.process = subprocess.Popen( + shlex.split(self.command), + stdin=self.slave, + stdout=self.slave, + stderr=self.slave, + bufsize=0, + universal_newlines=True + ) + async def read_output(self, ws): + """Reads process output and sends it to WebSocket.""" + loop = asyncio.get_event_loop() + while True: + try: + data = await loop.run_in_executor(None, os.read, self.master, 1024) + if not data: + break + await ws.send_bytes(data) # Send raw bytes for ANSI support + except Exception: + break + async def write_input(self, data): + """Writes user input to the process.""" + os.write(self.master, data.encode()) +How to run alpine with storage limitations and so on +How to run alpine with storage limitations and so on +How to run alpine using docker run with limitations for storage and cpu limitation and memory limitation +What is runc +How to use runc +ERRO[0000] runc run failed: unable to start container process: error during container init: exec: "/bin/sh": stat /bin/sh: no such file or directory +ERRO[0000] runc run failed: unable to start container process: error during container init: exec: "/bin/sh": stat /bin/sh: no such file or directory + +rrun docker in docker docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?. +c readline clear +How to use clear in c readline library +How to create your own xmpp server in python +How to use slixmpp server python package +how to serve server with slixmpp +ImportError: cannot import name 'XMPPServer' from 'slixmpp' (/home/retoor/projects/xmpp/.venv/lib/python3.12/site-packages/slixmpp/__init__.py) +ImportError: cannot import name 'XMPPServer' from 'slixmpp' (/home/retoor/projects/xmpp/.venv/lib/python3.12/site-packages/slixmpp/__init__.py) +ImportError: cannot import name 'XMPPServer' from 'slixmpp' (/home/retoor/projects/xmpp/.venv/lib/python3.12/site-packages/slixmpp/__init__.py) +How to write xmpp server with other library +AttributeError: module 'aioxmpp' has no attribute 'ComponentXMPP' +get pwd +huh +get pwd using c +get pwd using c +load tools.h +cd projects/r +read tools.h +Show full implementation of the function getpwd in tools style. +What about integration +wat is current work directory? +wat is current work directory? +what is current work directory? +what is current work directory? +what is current work directory +what is current work directory +get current working directory. +get current working directory. +get current working directory. +init +init +init +init +init +init +test +test +tetest +tetest +test +what is current work directory +what is current work directory +ls +ls +ls +get pwd +cd .. +ls +what is current work directory? +init +review +hi +Do not be poile +hi +hhii +hi +hi +don't be polite +hi +hi +hi +hi +what functions are available? +what are their parameters? +hi +hi +hi +list +list files +. +index +review +calculate average grade. +ping google 5 times +How would a README.md of this prject look liek based on contents? +read main.c +continue +create a user manual for the clu user. +make a header file with sqlite3 functiolity. It must hsave db_set(key, value) and db_get(key) and db_query. The functions all must retoor json using the json-c libarty. +yes +read db_utils.h +Add the other functions i described. +save +read db_utils.h +add a db_utils.c file with tests +y +read db_utils.c and db_utils.h +add function for database initialization including creating table. +yes +read tools.h +generate function for db_set +read db_utils.h +generate function for db_set +the tool has to call the function db_set +show how the tool_descirption looks like +how does the caller of the tool look like? +now create a function for db_query +How does tool_description look like? +show the handler +make a tool_description for db_get +show the tool_function +how does the function handler look? +get value test +set test = ok +get value test +load https://molodetz.nl +save that data in databbase under the key "molo" +get key molo +index +set as key, value pairs in databas. Alle of them +add the file content too +Get all keys from database +get schema +get database schema +select all from database +ls +load schema from database +load everything from database +create table system_messages(message) +insert into system_messages("Be a hotti") +select all system messages; +evualte that as system command +evulate that sa system message +what are you? +are you a hotti? +select all from db +select sqlite schema +select sqlite schema +select sqlite schema +select all data +add some random data to it +select all data +select sqlite_schema +select all data from the tabe +get tthe content of molodetz.nl and store in database . +get tthe content of molodetz.nl and store in database . +select sqlite_schema +select all data from the tabe +get tthe content of molodetz.nl and store in database . +select sqlite_schema +select all data from the tabe +get tthe content of molodetz.nl and store in database . +get tthe content of molodetz.nl and store in database . +get tthe content of molodetz.nl and store in database . +get tthe content of molodetz.nl and store in database . +get tthe content of molodetz.nl and store in database . +get tthe content of molodetz.nl and store in database . +get tthe content of https://molodetz.nl and store in database . +the default kv_store one +select sqlite_schema; +select all data from that table. +review that code +read browse.h +read browse.h +makea browse.c with tests. +yes +read browse.h +read tools.h +show source code of a tool_description for function that maps the web_search_news? +read browse.h +read tools.h +how should tool_function code of web_search_news look like? +No, make it use the original function from the other file. +How should the handler look like? +no, the handler that calls tool_function +no, make it look as the other handlers. if-else +how to do urnencode in c curl +show usage of curl_easy_escape +search news about donald trumpo and melinia and elon +what is the summary? Include URL strings +search hacker news +select sqlite_schema +> dump all search results in key value store + dump all search values in there +more details as value please +create a sh script and store it in kv store: +``` +run shell_script that you can get from database. +ok diff --git a/Makefile b/Makefile index 6da7674..bbf61db 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ all: build build_rpylib run # Variables for compiler and flags CC = gcc -CFLAGS = -Ofast -Werror -Wall -lreadline -lncurses -lcurl -lssl -lcrypto -ljson-c -lm +CFLAGS = -Ofast -Werror -Wall -lreadline -lncurses -lcurl -lssl -lcrypto -ljson-c -lm -lsqlite3 # Targets build: @@ -14,4 +14,4 @@ build_rpylib: publish rpylib.so run: - ./r + ./r --verbose diff --git a/browse.c b/browse.c new file mode 100644 index 0000000..49f6f10 --- /dev/null +++ b/browse.c @@ -0,0 +1,15 @@ +#include "browse.h" + +int main() { + char *query = "example"; + char *result = get_news(query); + + if (result) { + printf("Result: %s\n", result); + free(result); // Free the allocated memory for the result + } else { + printf("Failed to fetch news.\n"); + } + + return 0; +} \ No newline at end of file diff --git a/browse.h b/browse.h new file mode 100644 index 0000000..51c9a96 --- /dev/null +++ b/browse.h @@ -0,0 +1,41 @@ +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <curl/curl.h> +#include <json-c/json.h> +#include <json-c/json_util.h> +#include "http_curl.h" + + +char * url_encode(char *s){ + return curl_easy_escape(NULL, s, 0); +} + +char * web_search_news(char * q){ + char * news = malloc(4096); + news[0] = 0; + char * q_encoded = url_encode(q); + sprintf(news, "https://search.molodetz.nl/search?q=%s&format=json&categories=news",q_encoded); + free(q_encoded); + char * ret = curl_get(news); + free(news); + json_object * json_ret = json_tokener_parse(ret); + + json_object * json_results = json_object_object_get(json_ret, "results"); + json_object * json_result = json_object_array_get_idx(json_results, 0); + if(!json_result){ + json_object_put(json_ret); + free(ret); + return web_search_news(q); + } + json_object_put(json_ret); + return ret; +} +char * web_search_engine(char * q){ + char * searx = malloc(4096); + searx[0] = 0; + sprintf(searx, "https://searx.molodetz.nl/search?q=%s&format=json", q); + char * ret = curl_get(searx); + free(searx); + return ret; +} diff --git a/cmd.sh b/cmd.sh new file mode 100644 index 0000000..615a3c1 --- /dev/null +++ b/cmd.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +echo "š Analyzing disk usage... Please wait." + +# 1. Show overall disk usage +echo -e "\nš Disk Usage Overview:" +df -h + +# 2. Show the largest directories in / +echo -e "\nš Top 10 Largest Directories in Root (/):" +du -ahx / 2>/dev/null | sort -rh | head -10 + +# 3. Show the largest directories in /home +echo -e "\nš Top 10 Largest Directories in /home:" +du -ahx /home 2>/dev/null | sort -rh | head -10 + +# 4. Show the largest files over 1GB +echo -e "\nš Top 10 Largest Files Over 1GB:" +find / -type f -size +1G -exec ls -lh {} + 2>/dev/null | sort -k5 -rh | head -10 + +# 5. Check system logs +echo -e "\nš Checking Large Log Files in /var/log:" +sudo du -sh /var/log/* 2>/dev/null | sort -rh | head -10 + +# 6. Find large installed packages (Debian-based) +if command -v dpkg-query &> /dev/null; then + echo -e "\nš¦ Top 10 Largest Installed Packages (Debian-based):" + dpkg-query -Wf '${Installed-Size}\t${Package}\n' | sort -rh | head -10 +fi + +# 7. Find large installed packages (RPM-based) +if command -v dnf &> /dev/null; then + echo -e "\nš¦ Top 10 Largest Installed Packages (Fedora-based):" + dnf list installed | awk '{print $2, $1}' | sort -rh | head -10 +fi + +echo -e "\nā Disk Usage Analysis Completed!" diff --git a/database.db b/database.db new file mode 100644 index 0000000000000000000000000000000000000000..1c6819f6ee76450a515b2728dc6694ad2340e3fa GIT binary patch literal 24576 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 literal 0 HcmV?d00001 diff --git a/db_utils.c b/db_utils.c new file mode 100644 index 0000000..5ea21e1 --- /dev/null +++ b/db_utils.c @@ -0,0 +1,59 @@ +#include <stdio.h> +#include "db_utils.h" + +void db_initialize() { + sqlite3 *db; + char *err_msg = 0; + int rc = sqlite3_open("database.db", &db); + + if (rc != SQLITE_OK) { + return; + } + + const char *sql = "CREATE TABLE IF NOT EXISTS kv_store (key TEXT PRIMARY KEY, value TEXT);"; + rc = sqlite3_exec(db, sql, 0, 0, &err_msg); + + if (rc != SQLITE_OK) { + sqlite3_free(err_msg); + } + + sqlite3_close(db); +} + +void test_db_set() { + json_object *result = db_set("test_key", "test_value"); + if (result) { + printf("db_set: %s\n", json_object_get_string(result)); + json_object_put(result); + } else { + printf("db_set failed\n"); + } +} + +void test_db_get() { + json_object *result = db_get("test_key"); + if (result) { + printf("db_get: %s\n", json_object_to_json_string(result)); + json_object_put(result); + } else { + printf("db_get failed\n"); + } +} + +void test_db_query() { + json_object *result = db_query("SELECT * FROM kv_store"); + if (result) { + printf("db_query: %s\n", json_object_to_json_string(result)); + json_object_put(result); + } else { + printf("db_query failed\n"); + } +} + +int main() { + db_initialize(); + test_db_set(); + test_db_get(); + test_db_query(); + return 0; +} \ No newline at end of file diff --git a/db_utils.h b/db_utils.h new file mode 100644 index 0000000..f5544cf --- /dev/null +++ b/db_utils.h @@ -0,0 +1,141 @@ +#ifndef DB_UTILS_H +#define DB_UTILS_H + +#include <sqlite3.h> +#include <json-c/json.h> +#include "utils.h" + +const char * db_file = "~/.r.db"; + +char * db_file_expanded(){ + char * expanded = expand_home_directory(db_file); + static char result[4096]; + result[0] = 0; + strcpy(result, expanded); + free(expanded); + return result; +} + +void db_initialize(); +json_object * db_set(const char *key, const char *value); +json_object* db_get(const char *key); +json_object* db_query(const char *query); + + +void db_initialize() { + sqlite3 *db; + char *err_msg = 0; + int rc = sqlite3_open(db_file_expanded(), &db); + + if (rc != SQLITE_OK) { + return; + } + + const char *sql = "CREATE TABLE IF NOT EXISTS kv_store (key TEXT PRIMARY KEY, value TEXT);"; + rc = sqlite3_exec(db, sql, 0, 0, &err_msg); + + if (rc != SQLITE_OK) { + sqlite3_free(err_msg); + } + + sqlite3_close(db); +} + + +json_object * db_set(const char *key, const char *value) { + sqlite3 *db; + char *err_msg = 0; + int rc = sqlite3_open(db_file_expanded(), &db); + + if (rc != SQLITE_OK) { + return NULL; + } + + char *sql = sqlite3_mprintf("INSERT INTO kv_store (key, value) VALUES (%Q, %Q)", key, value); + rc = sqlite3_exec(db, sql, 0, 0, &err_msg); + sqlite3_free(sql); + + if (rc != SQLITE_OK) { + sqlite3_free(err_msg); + sqlite3_close(db); + return NULL; + } + + sqlite3_close(db); + return json_object_new_string("Success"); +} + +json_object* db_get(const char *key) { + sqlite3 *db; + sqlite3_stmt *stmt; + json_object *result = json_object_new_object(); + const char *value = NULL; + + int rc = sqlite3_open(db_file_expanded(), &db); + if (rc != SQLITE_OK) { + return NULL; + } + + const char *sql = "SELECT value FROM kv_store WHERE key = ?"; + sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); + sqlite3_bind_text(stmt, 1, key, -1, SQLITE_STATIC); + + if (sqlite3_step(stmt) == SQLITE_ROW) { + value = (const char *)sqlite3_column_text(stmt, 0); + } + + if (value) { + json_object_object_add(result, "value", json_object_new_string(value)); + } else { + json_object_object_add(result, "error", json_object_new_string("Key not found")); + } + + sqlite3_finalize(stmt); + sqlite3_close(db); + return result; +} +json_object* db_query(const char *query) { + sqlite3 *db; + sqlite3_stmt *stmt; + json_object *result = json_object_new_array(); + + int rc = sqlite3_open(db_file_expanded(), &db); + if (rc != SQLITE_OK) { + return NULL; + } + + sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + while (sqlite3_step(stmt) == SQLITE_ROW) { + json_object *row = json_object_new_object(); + for (int i = 0; i < sqlite3_column_count(stmt); i++) { + const char *col_name = sqlite3_column_name(stmt, i); + switch (sqlite3_column_type(stmt, i)) { + case SQLITE_INTEGER: + json_object_object_add(row, col_name, json_object_new_int64(sqlite3_column_int64(stmt, i))); + break; + case SQLITE_FLOAT: + json_object_object_add(row, col_name, json_object_new_double(sqlite3_column_double(stmt, i))); + break; + case SQLITE_TEXT: + json_object_object_add(row, col_name, json_object_new_string((const char *)sqlite3_column_text(stmt, i))); + break; + case SQLITE_BLOB: + json_object_object_add(row, col_name, json_object_new_string_len((const char *)sqlite3_column_blob(stmt, i), sqlite3_column_bytes(stmt, i))); + break; + case SQLITE_NULL: + default: + json_object_object_add(row, col_name, json_object_new_string("NULL")); + break; + } + } + json_object_array_add(result, row); + } + + sqlite3_finalize(stmt); + sqlite3_close(db); + + return result; +} + + +#endif // DB_UTILS_H diff --git a/indexer.h b/indexer.h new file mode 100644 index 0000000..ff8324c --- /dev/null +++ b/indexer.h @@ -0,0 +1,133 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dirent.h> +#include <sys/stat.h> +#include <time.h> +#include <json-c/json.h> +#include <limits.h> +#include <unistd.h> +#define MAX_FILES 20000 +#define MAX_PATH 4096 + +static const char *extensions[] = {".c", ".cpp", ".h", ".py", ".java", ".js", ".mk", ".html", "Makefile", ".css", ".json", ".cs", ".csproj", ".sln", ".toml",".rs"}; +static size_t ext_count = sizeof(extensions) / sizeof(extensions[0]); // Updated count to reflect the new number of extensions + + + +typedef struct { + char name[MAX_PATH]; + char modification_date[20]; + char creation_date[20]; + char type[10]; + size_t size_bytes; +} FileInfo; + +FileInfo file_list[MAX_FILES]; +size_t file_count = 0; + +int is_valid_extension(const char *filename, const char *extensions[], size_t ext_count) { + const char *dot = strrchr(filename, '.'); + if(!dot){ + dot = filename; +} + for (size_t i = 0; i < ext_count; i++) { + if (strcmp(dot, extensions[i]) == 0) { + return 1; + } + } + return 0; +} + +int is_ignored_directory(const char *dir_name) { + const char *ignored_dirs[] = {"env", ".venv", "node_modules", "venv", "virtualenv"}; + for (size_t i = 0; i < sizeof(ignored_dirs) / sizeof(ignored_dirs[0]); i++) { + if (strcmp(dir_name, ignored_dirs[i]) == 0) { + return 1; + } + } + return 0; +} + +void get_file_info(const char *path) { + struct stat file_stat; + if (stat(path, &file_stat) == 0) { + FileInfo info; + strncpy(info.name, path, MAX_PATH - 1); // Copy with one less to leave space for null terminator + info.name[MAX_PATH - 1] = '\0'; // Ensure null termination + strftime(info.modification_date, sizeof(info.modification_date), "%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_mtime)); + strftime(info.creation_date, sizeof(info.creation_date), "%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_ctime)); + strncpy(info.type, S_ISDIR(file_stat.st_mode) ? "directory" : "file", 10); + info.type[9] = '\0'; // Ensure null termination + info.size_bytes = file_stat.st_size; + file_list[file_count++] = info; + } +} + +char* index_directory(const char *dir_path) { + DIR *dir = opendir(dir_path); + struct dirent *entry; + if (dir == NULL) { + perror("Failed to open directory"); + return NULL; + } + + json_object *jarray = json_object_new_array(); + + while ((entry = readdir(dir)) != NULL) { + if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { + if (entry->d_name[0] == '.' || is_ignored_directory(entry->d_name)) { + continue; + } + char full_path[MAX_PATH]; + snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, entry->d_name); + if (entry->d_type == DT_DIR) { + char *subdir_json = index_directory(full_path); + if (subdir_json) { + json_object *jsubdir = json_object_new_string(subdir_json); + json_object_array_add(jarray, jsubdir); + free(subdir_json); + } + } else if (is_valid_extension(entry->d_name, extensions, ext_count)) { + get_file_info(full_path); + json_object *jfile = json_object_new_object(); + json_object_object_add(jfile, "file_name", json_object_new_string(file_list[file_count - 1].name)); + json_object_object_add(jfile, "modification_date", json_object_new_string(file_list[file_count - 1].modification_date)); + json_object_object_add(jfile, "creation_date", json_object_new_string(file_list[file_count - 1].creation_date)); + json_object_object_add(jfile, "type", json_object_new_string(file_list[file_count - 1].type)); + json_object_object_add(jfile, "size_bytes", json_object_new_int64(file_list[file_count - 1].size_bytes)); + + // Read the file contents + FILE *fp = fopen(file_list[file_count - 1].name, "r"); + if (fp != NULL) { + fseek(fp, 0, SEEK_END); + long length = ftell(fp); + fseek(fp, 0, SEEK_SET); + char *content = malloc(length + 1); + if (content) { + size_t bytesRead = fread(content, 1, length, fp); + if (bytesRead != length) { + free(content); + content = NULL; + json_object_object_add(jfile, "file_current_content_data", json_object_new_string("Error reading file")); + } else { + content[length] = '\0'; // Null-terminate the string + json_object_object_add(jfile, "file_current_content_data", json_object_new_string(content)); + } + free(content); + } + fclose(fp); + } else { + json_object_object_add(jfile, "content", json_object_new_string("Unable to read file")); + } + + json_object_array_add(jarray, jfile); + } + } + } + closedir(dir); + + char *result = strdup(json_object_to_json_string(jarray)); + json_object_put(jarray); + return result; +} diff --git a/main.c b/main.c index 5a6d581..a1e3de7 100644 --- a/main.c +++ b/main.c @@ -44,6 +44,8 @@ #include <string.h> #include <unistd.h> #include "utils.h" +#include "r.h" +#include "db_utils.h" volatile sig_atomic_t sigint_count = 0; time_t first_sigint_time = 0; @@ -76,7 +78,11 @@ char *get_prompt_from_args(int c, char **argv) { if (!strcmp(argv[i],"--stdin")){ fprintf(stderr, "%s\n", "Reading from stdin."); get_from_std_in = true; - }else if(!strcmp(argv[i],"--py")){ + }else if(!strcmp(argv[i],"--verbose")){ + is_verbose = true; + } + + else if(!strcmp(argv[i],"--py")){ if(i+1 <= c){ char * py_file_path = expand_home_directory(argv[i+1]); fprintf(stderr, "Including \"%s\".\n", py_file_path); @@ -334,7 +340,7 @@ void handle_sigint(int sig) { int main(int argc, char *argv[]) { signal(SIGINT, handle_sigint); - + db_initialize(); init(); if (try_prompt(argc, argv)) return 0; diff --git a/openai.h b/openai.h index 1246425..f944df9 100644 --- a/openai.h +++ b/openai.h @@ -54,14 +54,23 @@ struct json_object* openai_process_chat_message(const char* api_url, const char* } struct json_object *error_object; if (json_object_object_get_ex(parsed_json, "error", &error_object)) { - json_object_put(parsed_json); + 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); + + fprintf(stderr,"%s\n",json_object_to_json_string(parsed_json)); + + json_object_put(parsed_json); messages_remove_last(); + messages_remove_last(); + return NULL; } diff --git a/r.h b/r.h new file mode 100644 index 0000000..93cc28c --- /dev/null +++ b/r.h @@ -0,0 +1,8 @@ +#ifndef R_H +#define R_H +#include <stdbool.h> + +bool is_verbose = false; + + +#endif diff --git a/rpylib.so b/rpylib.so new file mode 100755 index 0000000000000000000000000000000000000000..3fe6a56be8396518c98b2b83f8425c2a19874be2 GIT binary patch literal 76312 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 KIO`fOaPlv>cSh&{ literal 0 HcmV?d00001 diff --git a/script.sh b/script.sh new file mode 100644 index 0000000..c839978 --- /dev/null +++ b/script.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +echo "This is a sample shell script." +echo "Running some commands..." + +# Add your commands below + +# Example command +ls -la diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..e5bfaf7 --- /dev/null +++ b/setup.py @@ -0,0 +1,10 @@ +from setuptools import setup, Extension + +module = Extension("rpylib", sources=["rpylib.c"]) + +setup( + name="rpylib", + version="1.0", + description="AI Module", + ext_modules=[module], +) diff --git a/tools.h b/tools.h index b7c9012..99f249e 100644 --- a/tools.h +++ b/tools.h @@ -26,6 +26,9 @@ #include <string.h> #include "indexer.h" +#include "db_utils.h" +#include "r.h" +#include "browse.h" struct json_object* tool_description_http_get(); struct json_object* tool_description_linux_terminal(); @@ -35,6 +38,12 @@ 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* tool_description_index_source_directory(); +struct json_object* tool_description_chdir(); +struct json_object* tool_description_getpwd(); +struct json_object* tool_description_db_set(); +struct json_object* tool_description_db_query(); +struct json_object* tool_description_db_get(); +struct json_object* tool_description_web_search_news(); struct json_object* tools_descriptions() { struct json_object* root = json_object_new_array(); @@ -46,16 +55,228 @@ struct json_object* tools_descriptions() { json_object_array_add(root, tool_description_directory_rglob()); json_object_array_add(root, tool_description_linux_terminal_interactive()); json_object_array_add(root,tool_description_index_source_directory()); + json_object_array_add(root,tool_description_chdir()); + json_object_array_add(root,tool_description_getpwd()); + json_object_array_add(root,tool_description_db_set()); + json_object_array_add(root, tool_description_db_query()); + json_object_array_add(root, tool_description_db_get()); + json_object_array_add(root, tool_description_web_search_news()); return root; } +char* tool_function_web_search_news(char* query) { + if (query == NULL) { + return strdup("Query cannot be NULL."); + } + + char* result = web_search_news(query); + if (result == NULL) { + return strdup("Failed to fetch news."); + } + + return result; +} + + +struct json_object* tool_description_web_search_news() { + 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("web_search_news")); + json_object_object_add(function, "description", json_object_new_string("Searches for news articles based on a query.")); + + 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* query = json_object_new_object(); + json_object_object_add(query, "type", json_object_new_string("string")); + json_object_object_add(query, "description", json_object_new_string("The url encoded query string to search for news articles.")); + json_object_object_add(properties, "query", query); + + json_object_object_add(parameters, "properties", properties); + + struct json_object* required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("query")); + 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_db_get(char* key) { + json_object* result = db_get(key); + if (result == NULL) { + return strdup("Failed to retrieve value from the database."); + } + + char* response = strdup(json_object_to_json_string(result)); + json_object_put(result); // Free the json_object + return response; +} + + + + +struct json_object* tool_description_db_get() { + 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("db_get")); + json_object_object_add(function, "description", json_object_new_string("Retrieves a value from the database for a given key.")); + + 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* key = json_object_new_object(); + json_object_object_add(key, "type", json_object_new_string("string")); + json_object_object_add(key, "description", json_object_new_string("The key to retrieve from the database.")); + json_object_object_add(properties, "key", key); + + json_object_object_add(parameters, "properties", properties); + + struct json_object* required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("key")); + 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_db_query(char* query) { + json_object* result = db_query(query); + if (result == NULL) { + return strdup("Failed to execute query on the database."); + } + + char* response = strdup(json_object_to_json_string(result)); + + + json_object_put(result); // Free the json_object + return response; +} +struct json_object* tool_description_db_query() { + 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("db_query")); + json_object_object_add(function, "description", json_object_new_string("Executes a query on the database and returns the results.")); + + 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* query = json_object_new_object(); + json_object_object_add(query, "type", json_object_new_string("string")); + json_object_object_add(query, "description", json_object_new_string("The SQL query to execute.")); + json_object_object_add(properties, "query", query); + + json_object_object_add(parameters, "properties", properties); + + struct json_object* required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("query")); + 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_db_set(char* key, char* value) { + json_object* result = db_set(key, value); + if (result == NULL) { + return strdup("Failed to set value in the database."); + } + + const char* response = json_object_get_string(result); + json_object_put(result); // Free the json_object + return strdup(response); +} +struct json_object* tool_description_db_set() { + 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("db_set")); + json_object_object_add(function, "description", json_object_new_string("Sets a value in the database for a given key.")); + + 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* key = json_object_new_object(); + json_object_object_add(key, "type", json_object_new_string("string")); + json_object_object_add(key, "description", json_object_new_string("The key to set in the database.")); + json_object_object_add(properties, "key", key); + + struct json_object* value = json_object_new_object(); + json_object_object_add(value, "type", json_object_new_string("string")); + json_object_object_add(value, "description", json_object_new_string("The value to set for the given key.")); + json_object_object_add(properties, "value", value); + + json_object_object_add(parameters, "properties", properties); + + struct json_object* required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("key")); + json_object_array_add(required, json_object_new_string("value")); + 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_http_get(char* url) { - fprintf(stderr, "Tool http_get: %s\n", url); return curl_get(url); } +char* tool_function_chdir(char* path) { + if (chdir(path) != 0) { + perror("chdir failed"); + return strdup("Failed to change directory!"); + } + + return strdup("Directory successfully changed."); +} + + + char* tool_function_linux_terminal(char* command) { - fprintf(stderr, "Tool linux_terminal: %s\n", command); FILE* fp; char buffer[1024]; size_t total_size = 0; @@ -77,7 +298,8 @@ char* tool_function_linux_terminal(char* command) { return strdup("Failed to allocate memory!"); } output = new_output; - printf("%s", output); + if(is_verbose) + fprintf(stderr, "%s", buffer); strcpy(output + total_size, buffer); total_size += chunk_size; } @@ -87,8 +309,6 @@ char* tool_function_linux_terminal(char* command) { } char* tool_function_linux_terminal_interactive(char* command) { - fprintf(stderr, "Tool linux_terminal_interactive: %s\n", command); - int result_code = system(command); char* result = malloc(100); @@ -98,6 +318,77 @@ char* tool_function_linux_terminal_interactive(char* command) { return result; } +char* tool_function_getpwd() { + char* cwd = (char*)malloc(PATH_MAX); + if (cwd == NULL) { + perror("Memory allocation failed"); + return strdup("Failed to allocate memory for current working directory!"); + } + + if (getcwd(cwd, PATH_MAX) == NULL) { + free(cwd); + perror("getcwd failed"); + return strdup("Failed to get current working directory!"); + } + + return cwd; +} + +struct json_object* tool_description_getpwd() { + 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("getpwd")); + json_object_object_add(function, "description", json_object_new_string("Returns the current working directory as a string.")); + + struct json_object* parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); + + + + json_object_object_add(function, "parameters", json_object_new_null()); + + json_object_object_add(root, "function", function); + + return root; +} + +struct json_object* tool_description_chdir() { + 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("chdir")); + json_object_object_add(function, "description", json_object_new_string("Changes the current working directory to the specified path. Call this function when `cd` is prompted.")); + + 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 change the current working directory to.")); + 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; +} + + + struct json_object* tool_description_index_source_directory() { struct json_object* root = json_object_new_object(); json_object_object_add(root, "type", json_object_new_string("function")); @@ -273,14 +564,12 @@ struct json_object* tool_description_write_file() { } char* tool_function_index_source_directory(char * path){ - fprintf(stderr, "Tool index_source_directory: %s\n", path); return index_directory(path); } char* tool_function_read_file(char* path) { char * expanded_path = expand_home_directory(path); - fprintf(stderr, "Tools read_file: %s\n", expanded_path); FILE* fp = fopen(expanded_path, "r"); free(expanded_path); @@ -308,7 +597,6 @@ char* tool_function_read_file(char* path) { } 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"); @@ -418,7 +706,6 @@ void recursive_glob(const char* pattern, glob_t* results) { } 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; @@ -458,7 +745,6 @@ char* tool_function_directory_rglob(char* target_dir) { } 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]; @@ -629,6 +915,14 @@ struct json_object* tools_execute(struct json_object* tools_array) { char* function_name = NULL; if (json_object_object_get_ex(function_obj, "name", &name_obj)) { function_name = (char*)json_object_get_string(name_obj); + 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)); + + if(is_verbose) + fprintf(stderr, "Executing function %s with arguments %s\n", function_name, json_object_to_json_string(arguments)); + } + } if (!strcmp(function_name, "linux_terminal_execute")) { @@ -655,7 +949,19 @@ struct json_object* tools_execute(struct json_object* tools_array) { free(terminal_result); } } - } else if (!strcmp(function_name, "directory_glob")) { + }else if (!strcmp(function_name, "chdir")) { + 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* chdir_result = tool_function_chdir(path); + json_object_object_add(tool_result, "content", json_object_new_string(chdir_result)); + free(chdir_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)); @@ -709,7 +1015,38 @@ struct json_object* tools_execute(struct json_object* tools_array) { free(write_result); } } - } else if (!strcmp(function_name, "index_source_directory")) { + }else if (!strcmp(function_name, "db_query")) { + 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* query_obj; + + if (json_object_object_get_ex(arguments, "query", &query_obj)) { + char* query = (char*)json_object_get_string(query_obj); + char * db_query_result = tool_function_db_query(query); + json_object_object_add(tool_result, "content", json_object_new_string( db_query_result));; + if(db_query_result != NULL) + free(db_query_result); + } + } +} else if (!strcmp(function_name, "db_set")) { + 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* key_obj; + struct json_object* value_obj; + + if (json_object_object_get_ex(arguments, "key", &key_obj) && + json_object_object_get_ex(arguments, "value", &value_obj)) { + char* key = (char*)json_object_get_string(key_obj); + char* value = (char*)json_object_get_string(value_obj); + char* db_set_result = tool_function_db_set(key, value); + json_object_object_add(tool_result, "content", json_object_new_string(db_set_result)); + free(db_set_result); + } + } + + }else if (!strcmp(function_name, "index_source_directory")) { 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)); @@ -721,7 +1058,37 @@ struct json_object* tools_execute(struct json_object* tools_array) { free(listing_result); } } - } else if (!strcmp(function_name, "directory_rglob")) { + }else if (!strcmp(function_name, "web_search_news")){ + 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* query_obj; + if (json_object_object_get_ex(arguments, "query", &query_obj)) { + char* query = (char*)json_object_get_string(query_obj); + char* news_result = tool_function_web_search_news(query); + json_object_object_add(tool_result, "content", json_object_new_string(news_result)); + free(news_result); + } + } + }else if (!strcmp(function_name, "db_get")) { + 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* key_obj; + + if (json_object_object_get_ex(arguments, "key", &key_obj)) { + char* key = (char*)json_object_get_string(key_obj); + char* db_get_result = tool_function_db_get(key); + json_object_object_add(tool_result, "content", json_object_new_string(db_get_result)); + free(db_get_result); + } + } +}else if (!strcmp(function_name, "getpwd")) { + char* pwd_result = tool_function_getpwd(); + json_object_object_add(tool_result, "content", json_object_new_string(pwd_result)); + free(pwd_result); + } + 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));