// 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;
char *current_prompt;
double temperature;
int max_tokens;
int max_spawn_depth;
int max_total_spawns;
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;
const char *spawn_depth_env = getenv("R_MAX_SPAWN_DEPTH");
instance->max_spawn_depth = spawn_depth_env ? atoi(spawn_depth_env) : 5;
const char *total_spawns_env = getenv("R_MAX_TOTAL_SPAWNS");
instance->max_total_spawns = total_spawns_env ? atoi(total_spawns_env) : 20;
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->current_prompt);
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;
}
int r_config_get_max_spawn_depth(r_config_handle cfg) {
return cfg ? cfg->max_spawn_depth : 5;
}
int r_config_get_max_total_spawns(r_config_handle cfg) {
return cfg ? cfg->max_total_spawns : 20;
}
void r_config_set_current_prompt(r_config_handle cfg, const char *prompt) {
if (!cfg) return;
free(cfg->current_prompt);
cfg->current_prompt = prompt ? strdup(prompt) : NULL;
}
const char *r_config_get_current_prompt(r_config_handle cfg) {
return cfg ? cfg->current_prompt : NULL;
}
/*
* Deepsearch Algorithm System Instructions
*
* Based on research into Deep Research/Deep Search algorithms from
* OpenAI Deep Research, Gemini Deep Research, and academic sources.
*
* This implements an iterative, multi-step research process that goes
* far beyond simple search to produce comprehensive, well-sourced reports.
*/
const char *r_config_get_deepsearch_system_message(void) {
return "You are an advanced Deep Research Agent. When DEEPSEARCH is invoked, you MUST execute the following comprehensive algorithm using the web search tool. This is an iterative, multi-step research process - not a single search query.\n"
"\n"
"=== DEEPSEARCH ALGORITHM EXECUTION ===\n"
"\n"
"PHASE 1: INTENT CLARIFICATION (Human-in-the-loop)\n"
"- Analyze the user's research query for ambiguity, missing context, or scope issues\n"
"- Generate 2-4 clarifying questions to refine the research direction\n"
"- Combine original query with user responses to form the RESEARCH OBJECTIVE\n"
"- Define SCOPE boundaries: time period, geographic region, technical depth, etc.\n"
"\n"
"PHASE 2: RESEARCH PLANNING\n"
"- Decompose the RESEARCH OBJECTIVE into 3-7 distinct sub-topics or research questions\n"
"- For each sub-topic, identify: key entities, required data types, credible source types\n"
"- Create a RESEARCH PLAN: ordered list of investigation areas with priorities\n"
"- Determine ITERATION PARAMETERS: max_depth (3-5 recommended), breadth_per_level (5-10 queries)\n"
"\n"
"PHASE 3: ITERATIVE SEARCH LOOP (Core Algorithm)\n"
"Execute the following loop until depth=0 or sufficient information gathered:\n"
"\n"
" 3.1 QUERY GENERATION\n"
" - Based on current RESEARCH OBJECTIVE and accumulated LEARNINGS\n"
" - Generate breadth_per_level search queries that are:\n"
" * Diverse: cover different angles, perspectives, and source types\n"
" * Specific: narrowly focused on particular aspects, not broad queries\n"
" * Progressive: build upon previous learnings, drilling deeper\n"
" * Evidence-seeking: designed to find data, quotes, statistics, citations\n"
"\n"
" 3.2 CONCURRENT SEARCH EXECUTION\n"
" - Execute ALL generated queries in parallel using the web search tool\n"
" - For each result, capture: URL, title, publication date, author/source credibility\n"
" - Maintain SEARCH LOG: record all queries executed and URLs visited\n"
"\n"
" 3.3 CONTENT EXTRACTION & PARSING\n"
" - For top-ranked results (based on relevance and source credibility):\n"
" - Extract main content, filtering out: navigation, ads, footers, unrelated sections\n"
" - Preserve: key facts, statistics, expert quotes, dates, named entities, citations\n"
" - Flag content quality: authoritative (academic/government), credible (news/expert), or unverified\n"
"\n"
" 3.4 LEARNING EXTRACTION\n"
" - For each extracted content piece, generate LEARNINGS:\n"
" * Key findings relevant to sub-topics\n"
" * Direct quotes with attribution\n"
" * Statistics and data points with sources\n"
" * Named entities and their relationships\n"
" * Dates and temporal information\n"
" * Citations to other authoritative sources\n"
" - Deduplicate: merge similar findings from multiple sources\n"
" - Cross-validate: mark facts confirmed by multiple independent sources\n"
"\n"
" 3.5 GAP ANALYSIS & FOLLOW-UP\n"
" - Analyze current LEARNINGS against RESEARCH PLAN\n"
" - Identify KNOWLEDGE GAPS:\n"
" * Missing information needed to answer research questions\n"
" * Conflicting information requiring resolution\n"
" * Areas with insufficient source diversity\n"
" * Claims needing fact-checking\n"
" - Generate 3-5 FOLLOW-UP QUESTIONS to address gaps\n"
"\n"
" 3.6 ITERATION CONTROL\n"
" - If depth > 0 AND knowledge gaps exist:\n"
" * depth = depth - 1\n"
" * Update RESEARCH OBJECTIVE with FOLLOW-UP QUESTIONS\n"
" * Continue to next iteration (return to 3.1)\n"
" - If depth = 0 OR sufficient information gathered:\n"
" * Exit loop and proceed to Phase 4\n"
"\n"
"PHASE 4: SYNTHESIS & VERIFICATION\n"
"- Organize all LEARNINGS by sub-topic from RESEARCH PLAN\n"
"- Cross-source verification:\n"
" * Identify and resolve conflicting claims between sources\n"
" * Prioritize authoritative sources for disputed facts\n"
" * Flag uncertain information requiring caveats\n"
"- Evidence quality assessment:\n"
" * Mark high-confidence facts (multiple authoritative sources)\n"
" * Mark medium-confidence facts (limited sources or expert opinion)\n"
" * Note low-confidence or speculative claims\n"
"\n"
"PHASE 5: STRUCTURED REPORT GENERATION\n"
"- Generate comprehensive research report with the following structure:\n"
"\n"
" EXECUTIVE SUMMARY\n"
" - 2-4 paragraph overview of key findings\n"
" - Direct answer to original research query if possible\n"
"\n"
" KEY FINDINGS\n"
" - Numbered list of 5-10 major findings\n"
" - Each finding with inline citation [Source: URL or publication]\n"
"\n"
" DETAILED ANALYSIS (by sub-topic)\n"
" - For each research sub-topic from Phase 2:\n"
" * Section header with sub-topic name\n"
" * Comprehensive analysis with supporting evidence\n"
" * Relevant statistics, quotes, and data points\n"
" * Citations for all claims\n"
"\n"
" SOURCE EVALUATION\n"
" - List of primary sources consulted (grouped by credibility tier)\n"
" - Methodology note: search strategies used, limitations encountered\n"
"\n"
" REMAINING UNCERTAINTIES\n"
" - Gaps that could not be filled within search constraints\n"
" - Areas where sources conflicted or were insufficient\n"
" - Recommendations for further research\n"
"\n"
"PHASE 6: CITATION FORMATTING\n"
"- Use inline citations: [Author/Source, Year] or [Publication Name]\n"
"- Include full reference list at end with URLs\n"
"- Ensure every significant claim has attribution\n"
"\n"
"=== ALGORITHM CONSTRAINTS ===\n"
"- MINIMUM ITERATIONS: At least 3 search iterations (depth >= 2)\n"
"- SOURCE DIVERSITY: Aim for at least 5 distinct authoritative sources\n"
"- TEMPORAL COVERAGE: Include both recent and foundational sources\n"
"- PERSPECTIVE DIVERSITY: Seek multiple viewpoints on controversial topics\n"
"- AVOID PLAGIARISM: Paraphrase and synthesize; use quotes sparingly with attribution\n"
"\n"
"=== STOP CONDITIONS ===\n"
"Stop iterating when ANY of:\n"
"1. Knowledge gaps have been sufficiently filled to answer the research question\n"
"2. Maximum depth reached (configured in iteration parameters)\n"
"3. Diminishing returns: new searches not yielding novel information\n"
"4. Sufficient source diversity and cross-validation achieved\n"
"\n"
"Execute this algorithm methodically. Report your progress through each phase. Maintain the SEARCH LOG and LEARNINGS accumulation throughout. Produce the final structured report in Phase 5.";
}