Files
sovereign_browser/src/agent_chat_store.c

178 lines
5.9 KiB
C

/*
* agent_chat_store.c — thin wrapper over db.c for agent chat sessions
*
* Manages the "current session" concept and provides convenience
* functions for adding messages and loading history in OpenAI format.
*/
#include "agent_chat_store.h"
#include "db.h"
#include <stdio.h>
#include <string.h>
/* ── Internal state ────────────────────────────────────────────────── */
/* Owned by the store; freed on replacement or shutdown. */
static char *g_current_session_id = NULL;
/* ── Helpers ───────────────────────────────────────────────────────── */
/*
* Replace g_current_session_id with a newly-allocated copy of `id`.
* Frees the previous value. Takes ownership of nothing (copies `id`).
* Returns a pointer to the stored string (owned by the store).
*/
static const char *store_session_id(const char *id) {
if (id == NULL) return NULL;
if (g_current_session_id) {
g_free(g_current_session_id);
}
g_current_session_id = g_strdup(id);
return g_current_session_id;
}
/* ── Public API ────────────────────────────────────────────────────── */
const char *agent_chat_store_get_session(void) {
if (g_current_session_id) {
return g_current_session_id;
}
/* Try to load the latest existing session. */
char *latest = db_agent_session_get_latest();
if (latest) {
const char *stored = store_session_id(latest);
g_free(latest);
return stored;
}
/* No sessions exist — create a new one. */
char *id = db_agent_session_create(NULL);
if (id == NULL) {
g_printerr("[agent_chat_store] failed to create new session\n");
return NULL;
}
const char *stored = store_session_id(id);
g_free(id);
return stored;
}
const char *agent_chat_store_new_session(const char *title) {
char *id = db_agent_session_create(title);
if (id == NULL) {
g_printerr("[agent_chat_store] failed to create new session\n");
return NULL;
}
const char *stored = store_session_id(id);
g_free(id);
return stored;
}
const char *agent_chat_store_set_session(const char *session_id) {
if (session_id == NULL) return NULL;
return store_session_id(session_id);
}
int agent_chat_store_add_user_message(const char *content) {
const char *sid = agent_chat_store_get_session();
if (sid == NULL) return -1;
if (content == NULL) return -1;
int row = db_agent_message_add(sid, "user", content, NULL, NULL);
if (row < 0) {
g_printerr("[agent_chat_store] failed to add user message\n");
return -1;
}
return 0;
}
int agent_chat_store_add_assistant_message(const char *content,
const char *tool_calls_json) {
const char *sid = agent_chat_store_get_session();
if (sid == NULL) return -1;
int row = db_agent_message_add(sid, "assistant", content,
tool_calls_json, NULL);
if (row < 0) {
g_printerr("[agent_chat_store] failed to add assistant message\n");
return -1;
}
return 0;
}
int agent_chat_store_add_tool_result(const char *tool_call_id,
const char *result_json) {
const char *sid = agent_chat_store_get_session();
if (sid == NULL) return -1;
if (tool_call_id == NULL || result_json == NULL) return -1;
int row = db_agent_message_add(sid, "tool", result_json, NULL,
tool_call_id);
if (row < 0) {
g_printerr("[agent_chat_store] failed to add tool result\n");
return -1;
}
return 0;
}
cJSON *agent_chat_store_get_messages(void) {
const char *sid = agent_chat_store_get_session();
if (sid == NULL) return NULL;
cJSON *raw = db_agent_message_list(sid);
if (raw == NULL) {
g_printerr("[agent_chat_store] failed to load messages\n");
return NULL;
}
/* Convert to OpenAI-format array. */
cJSON *out = cJSON_CreateArray();
cJSON *msg;
cJSON_ArrayForEach(msg, raw) {
cJSON *role_item = cJSON_GetObjectItemCaseSensitive(msg, "role");
const char *role = (cJSON_IsString(role_item))
? role_item->valuestring : "";
cJSON *content_item = cJSON_GetObjectItemCaseSensitive(msg, "content");
cJSON *tool_calls_item = cJSON_GetObjectItemCaseSensitive(msg, "tool_calls");
cJSON *tool_call_id_item = cJSON_GetObjectItemCaseSensitive(msg, "tool_call_id");
cJSON *obj = cJSON_CreateObject();
cJSON_AddStringToObject(obj, "role", role);
/* content: include only if non-null. */
if (cJSON_IsString(content_item)) {
cJSON_AddStringToObject(obj, "content", content_item->valuestring);
}
/* tool_calls: parse the stored JSON string into an array object. */
if (cJSON_IsString(tool_calls_item) &&
tool_calls_item->valuestring[0] != '\0') {
cJSON *parsed = cJSON_Parse(tool_calls_item->valuestring);
if (parsed) {
cJSON_AddItemToObject(obj, "tool_calls", parsed);
} else {
/* Store the raw string if it isn't valid JSON. */
cJSON_AddStringToObject(obj, "tool_calls",
tool_calls_item->valuestring);
}
}
/* tool_call_id: for role="tool". */
if (cJSON_IsString(tool_call_id_item)) {
cJSON_AddStringToObject(obj, "tool_call_id",
tool_call_id_item->valuestring);
}
cJSON_AddItemToArray(out, obj);
}
cJSON_Delete(raw);
return out;
}
const char *agent_chat_store_session_id(void) {
return g_current_session_id;
}