|
// retoor <retoor@molodetz.nl>
|
|
|
|
#include "r_config.h"
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
struct r_config_t {
|
|
char *api_url;
|
|
char *models_url;
|
|
char *model;
|
|
char *api_key;
|
|
char *db_path;
|
|
char *session_id;
|
|
char *system_message;
|
|
double temperature;
|
|
int max_tokens;
|
|
bool use_tools;
|
|
bool use_strict;
|
|
bool verbose;
|
|
};
|
|
|
|
static struct r_config_t *instance = NULL;
|
|
|
|
static char *strdup_safe(const char *s) {
|
|
return s ? strdup(s) : NULL;
|
|
}
|
|
|
|
static bool resolve_env_bool(const char *env_name, bool default_val) {
|
|
const char *val = getenv(env_name);
|
|
if (!val) return default_val;
|
|
if (!strcmp(val, "true") || !strcmp(val, "1")) return true;
|
|
if (!strcmp(val, "false") || !strcmp(val, "0")) return false;
|
|
return default_val;
|
|
}
|
|
|
|
static const char *resolve_api_key(void) {
|
|
|
|
const char * key = getenv("R_KEY");
|
|
if (key && *key) return key;
|
|
|
|
|
|
|
|
|
|
key = getenv("OPENROUTER_API_KEY");
|
|
if (key && *key) return key;
|
|
|
|
|
|
|
|
key = getenv("OPENAI_API_KEY");
|
|
if (key && *key) return key;
|
|
|
|
|
|
return "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";
|
|
}
|
|
|
|
static bool is_valid_session_id(const char *session_id) {
|
|
if (!session_id || !*session_id) return false;
|
|
if (strlen(session_id) > 255) return false;
|
|
|
|
for (const char *p = session_id; *p; p++) {
|
|
if (!isalnum((unsigned char)*p) && *p != '-' && *p != '_' && *p != '.') {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
r_config_handle r_config_get_instance(void) {
|
|
if (instance) return instance;
|
|
|
|
instance = calloc(1, sizeof(struct r_config_t));
|
|
if (!instance) return NULL;
|
|
|
|
const char *base_url = getenv("R_BASE_URL");
|
|
if (base_url && *base_url) {
|
|
size_t len = strlen(base_url);
|
|
instance->api_url = malloc(len + 32);
|
|
instance->models_url = malloc(len + 32);
|
|
if (instance->api_url && instance->models_url) {
|
|
snprintf(instance->api_url, len + 32, "%s/v1/chat/completions", base_url);
|
|
snprintf(instance->models_url, len + 32, "%s/v1/models", base_url);
|
|
}
|
|
} else {
|
|
instance->api_url = strdup("https://api.openai.com/v1/chat/completions");
|
|
instance->models_url = strdup("https://api.openai.com/v1/models");
|
|
}
|
|
|
|
const char *model = getenv("R_MODEL");
|
|
instance->model = strdup(model && *model ? model : "gpt-4o-mini");
|
|
|
|
instance->api_key = strdup(resolve_api_key());
|
|
instance->db_path = strdup("~/.r.db");
|
|
instance->temperature = 0.1;
|
|
const char *max_tokens_env = getenv("R_MAX_TOKENS");
|
|
instance->max_tokens = max_tokens_env ? atoi(max_tokens_env) : 4096;
|
|
instance->use_tools = resolve_env_bool("R_USE_TOOLS", true);
|
|
instance->use_strict = resolve_env_bool("R_USE_STRICT", true);
|
|
instance->verbose = false;
|
|
|
|
const char *session = getenv("R_SESSION");
|
|
if (session && is_valid_session_id(session)) {
|
|
instance->session_id = strdup(session);
|
|
} else {
|
|
instance->session_id = NULL;
|
|
}
|
|
|
|
instance->system_message = strdup_safe(getenv("R_SYSTEM_MESSAGE"));
|
|
|
|
return instance;
|
|
}
|
|
|
|
void r_config_destroy(void) {
|
|
if (!instance) return;
|
|
free(instance->api_url);
|
|
free(instance->models_url);
|
|
free(instance->model);
|
|
free(instance->api_key);
|
|
free(instance->db_path);
|
|
free(instance->session_id);
|
|
free(instance->system_message);
|
|
free(instance);
|
|
instance = NULL;
|
|
}
|
|
|
|
const char *r_config_get_api_url(r_config_handle cfg) {
|
|
return cfg ? cfg->api_url : NULL;
|
|
}
|
|
|
|
const char *r_config_get_models_url(r_config_handle cfg) {
|
|
return cfg ? cfg->models_url : NULL;
|
|
}
|
|
|
|
const char *r_config_get_model(r_config_handle cfg) {
|
|
return cfg ? cfg->model : NULL;
|
|
}
|
|
|
|
void r_config_set_model(r_config_handle cfg, const char *model) {
|
|
if (!cfg || !model) return;
|
|
free(cfg->model);
|
|
cfg->model = strdup(model);
|
|
}
|
|
|
|
const char *r_config_get_api_key(r_config_handle cfg) {
|
|
return cfg ? cfg->api_key : NULL;
|
|
}
|
|
|
|
const char *r_config_get_db_path(r_config_handle cfg) {
|
|
return cfg ? cfg->db_path : NULL;
|
|
}
|
|
|
|
bool r_config_use_tools(r_config_handle cfg) {
|
|
return cfg ? cfg->use_tools : true;
|
|
}
|
|
|
|
bool r_config_use_strict(r_config_handle cfg) {
|
|
return cfg ? cfg->use_strict : true;
|
|
}
|
|
|
|
bool r_config_is_verbose(r_config_handle cfg) {
|
|
return cfg ? cfg->verbose : false;
|
|
}
|
|
|
|
void r_config_set_verbose(r_config_handle cfg, bool verbose) {
|
|
if (cfg) cfg->verbose = verbose;
|
|
}
|
|
|
|
double r_config_get_temperature(r_config_handle cfg) {
|
|
return cfg ? cfg->temperature : 0.1;
|
|
}
|
|
|
|
int r_config_get_max_tokens(r_config_handle cfg) {
|
|
return cfg ? cfg->max_tokens : 4096;
|
|
}
|
|
|
|
const char *r_config_get_session_id(r_config_handle cfg) {
|
|
return cfg ? cfg->session_id : NULL;
|
|
}
|
|
|
|
bool r_config_set_session_id(r_config_handle cfg, const char *session_id) {
|
|
if (!cfg || !is_valid_session_id(session_id)) return false;
|
|
free(cfg->session_id);
|
|
cfg->session_id = strdup(session_id);
|
|
return cfg->session_id != NULL;
|
|
}
|
|
|
|
const char *r_config_get_system_message(r_config_handle cfg) {
|
|
return cfg ? cfg->system_message : NULL;
|
|
}
|