261 lines
7.4 KiB
C
Raw Normal View History

2025-01-04 08:40:31 +01:00
// Written by retoor@molodetz.nl
2025-03-28 06:56:36 +01:00
// This code manages a collection of messages using JSON objects. It provides
// functions to retrieve all messages as a JSON array, add a new message with a
// specified role and content, and free the allocated resources.
2025-01-04 08:40:31 +01:00
2025-01-27 19:06:59 +01:00
// Uses the external library <json-c/json.h> for JSON manipulation
2025-01-04 08:40:31 +01:00
// MIT License
2025-03-28 06:56:36 +01:00
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation 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.
2025-01-04 08:40:31 +01:00
2025-01-05 22:59:51 +01:00
#ifndef R_MESSAGES_H
#define R_MESSAGES_H
2025-01-27 19:06:59 +01:00
2025-05-05 14:33:08 +02:00
#include "db_utils.h"
2025-01-04 06:00:03 +01:00
#include "json-c/json.h"
2025-03-28 06:56:36 +01:00
#include "tools.h"
2025-12-26 07:24:13 +01:00
#include "utils.h"
2025-03-28 06:56:36 +01:00
#include <string.h>
2025-12-26 07:24:13 +01:00
#include <unistd.h>
2025-01-27 19:06:59 +01:00
struct json_object *message_array = NULL;
2025-12-26 07:24:13 +01:00
static char session_id[256] = {0};
static char override_session_id[256] = {0};
struct json_object *message_list();
bool set_session_id(const char *name) {
if (name == NULL || *name == '\0') {
return false;
}
size_t len = strlen(name);
if (len > 200) {
return false;
}
for (const char *p = name; *p; p++) {
if (*p == '/' || *p == '\\') {
return false;
}
}
strncpy(override_session_id, name, sizeof(override_session_id) - 1);
override_session_id[sizeof(override_session_id) - 1] = '\0';
return true;
}
const char *get_session_id() {
if (session_id[0] == '\0') {
if (override_session_id[0] != '\0') {
strncpy(session_id, override_session_id, sizeof(session_id) - 1);
session_id[sizeof(session_id) - 1] = '\0';
}
}
return session_id;
}
void init_session_id() {
if (session_id[0] != '\0') {
return;
}
if (override_session_id[0] != '\0') {
strncpy(session_id, override_session_id, sizeof(session_id) - 1);
session_id[sizeof(session_id) - 1] = '\0';
return;
}
char *tty = ttyname(STDIN_FILENO);
if (tty) {
unsigned long h = 5381;
for (char *p = tty; *p; p++) {
h = ((h << 5) + h) + (unsigned char)*p;
}
snprintf(session_id, sizeof(session_id), "%lu", h);
} else {
snprintf(session_id, sizeof(session_id), "%d", getppid());
}
}
char *get_session_db_key() {
static char key[512];
init_session_id();
snprintf(key, sizeof(key), "session:%s", session_id);
return key;
}
bool messages_save() {
char *key = get_session_db_key();
const char *json_str = json_object_to_json_string_ext(message_list(), JSON_C_TO_STRING_PLAIN);
if (!json_str) {
return false;
}
json_object *result = db_set(key, json_str);
if (result) {
json_object_put(result);
return true;
}
return false;
}
bool messages_load_conversation() {
char *key = get_session_db_key();
json_object *result = db_get(key);
if (!result) {
return false;
}
json_object *value_obj;
if (!json_object_object_get_ex(result, "value", &value_obj)) {
json_object_put(result);
return false;
}
const char *json_str = json_object_get_string(value_obj);
if (!json_str) {
json_object_put(result);
return false;
}
struct json_object *loaded = json_tokener_parse(json_str);
json_object_put(result);
if (!loaded || !json_object_is_type(loaded, json_type_array)) {
if (loaded) {
json_object_put(loaded);
}
return false;
}
int len = json_object_array_length(loaded);
int added = 0;
for (int i = 0; i < len; i++) {
struct json_object *msg = json_object_array_get_idx(loaded, i);
struct json_object *role_obj;
if (json_object_object_get_ex(msg, "role", &role_obj)) {
const char *role = json_object_get_string(role_obj);
if (role && strcmp(role, "system") != 0) {
json_object_array_add(message_list(), json_object_get(msg));
added++;
}
} else {
json_object_array_add(message_list(), json_object_get(msg));
added++;
}
}
json_object_put(loaded);
return added > 0;
}
2025-01-04 06:00:03 +01:00
2025-01-04 08:40:31 +01:00
struct json_object *message_list() {
2025-03-28 06:56:36 +01:00
if (!message_array) {
message_array = json_object_new_array();
}
return message_array;
2025-01-04 08:40:31 +01:00
}
2025-03-19 18:04:32 +01:00
bool messages_remove_last() {
2025-03-28 06:56:36 +01:00
struct json_object *messages = message_list();
int size = json_object_array_length(messages);
if (size) {
json_object_array_del_idx(messages, size - 1, 1);
2025-12-26 07:24:13 +01:00
messages_save();
2025-03-28 06:56:36 +01:00
return true;
}
return false;
2025-03-19 18:04:32 +01:00
}
2025-03-28 06:56:36 +01:00
void messages_remove() {
2025-12-26 07:24:13 +01:00
if (message_array) {
json_object_put(message_array);
message_array = NULL;
}
message_list();
messages_save();
2025-03-05 23:53:35 +01:00
}
2025-03-03 08:07:17 +01:00
struct json_object *message_add_tool_call(struct json_object *message) {
2025-03-28 06:56:36 +01:00
struct json_object *messages = message_list();
json_object_array_add(messages, message);
2025-12-26 07:24:13 +01:00
messages_save();
2025-03-28 06:56:36 +01:00
return message;
2025-03-03 08:07:17 +01:00
}
2025-03-03 17:06:05 +01:00
2025-03-28 06:56:36 +01:00
struct json_object *message_add_tool_result(const char *tool_call_id,
2025-04-08 10:17:27 +02:00
char *tool_result) {
2025-03-28 06:56:36 +01:00
struct json_object *messages = message_list();
struct json_object *message = json_object_new_object();
2025-12-18 01:08:38 +01:00
if (message == NULL) {
return NULL;
}
2025-03-03 08:07:17 +01:00
2025-03-28 06:56:36 +01:00
json_object_object_add(message, "tool_call_id",
json_object_new_string(tool_call_id));
2025-04-08 10:17:27 +02:00
2025-12-18 01:08:38 +01:00
size_t result_len = strlen(tool_result);
if (result_len > 104000) {
result_len = 104000;
2025-04-08 10:17:27 +02:00
}
2025-03-28 06:56:36 +01:00
json_object_object_add(message, "tool_result",
2025-12-18 01:08:38 +01:00
json_object_new_string_len(tool_result, (int)result_len));
2025-03-03 08:07:17 +01:00
2025-03-28 06:56:36 +01:00
json_object_array_add(messages, message);
2025-12-26 07:24:13 +01:00
messages_save();
2025-03-28 06:56:36 +01:00
return message;
2025-03-03 08:07:17 +01:00
}
2025-03-20 16:38:10 +01:00
void message_add_object(json_object *message) {
2025-03-28 06:56:36 +01:00
struct json_object *messages = message_list();
json_object_array_add(messages, message);
2025-12-26 07:24:13 +01:00
messages_save();
2025-03-20 16:38:10 +01:00
}
2025-03-30 00:13:42 +01:00
struct json_object *message_add(const char *role, const char *content);
2025-01-27 19:06:59 +01:00
struct json_object *message_add(const char *role, const char *content) {
2025-03-28 06:56:36 +01:00
struct json_object *messages = message_list();
struct json_object *message = json_object_new_object();
2025-12-18 01:08:38 +01:00
if (message == NULL) {
return NULL;
}
2025-03-28 06:56:36 +01:00
json_object_object_add(message, "role", json_object_new_string(role));
2025-05-05 14:33:08 +02:00
if (content) {
2025-12-18 01:08:38 +01:00
size_t content_len = strlen(content);
if (content_len > 1048570) {
content_len = 1048570;
2025-04-08 10:17:27 +02:00
}
2025-05-05 14:33:08 +02:00
json_object_object_add(message, "content",
2025-12-18 01:08:38 +01:00
json_object_new_string_len(content, (int)content_len));
2025-04-08 10:17:27 +02:00
}
2025-03-28 06:56:36 +01:00
if (!strcmp(role, "user")) {
json_object_object_add(message, "tools", tools_descriptions());
2025-05-05 14:33:08 +02:00
json_object_object_add(message, "parallel_tool_calls",
json_object_new_boolean(true));
2025-03-28 06:56:36 +01:00
}
2025-03-03 08:07:17 +01:00
2025-03-28 06:56:36 +01:00
json_object_array_add(messages, message);
2025-12-26 07:24:13 +01:00
if (strcmp(role, "system") != 0) {
messages_save();
}
2025-03-28 06:56:36 +01:00
return message;
2025-01-04 06:00:03 +01:00
}
2025-01-04 08:40:31 +01:00
char *message_json() {
2025-03-28 06:56:36 +01:00
return (char *)json_object_to_json_string_ext(message_list(),
JSON_C_TO_STRING_PRETTY);
2025-01-04 06:00:03 +01:00
}
2025-01-04 08:40:31 +01:00
void message_free() {
2025-03-28 06:56:36 +01:00
if (message_array) {
json_object_put(message_array);
message_array = NULL;
}
2025-01-04 06:00:03 +01:00
}
2025-01-27 19:06:59 +01:00
2025-03-19 18:04:32 +01:00
#endif