2026-01-28 19:34:39 +01:00
// 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 ;
2026-02-14 08:07:05 +01:00
char * current_prompt ;
2026-01-28 19:34:39 +01:00
double temperature ;
2026-01-29 06:01:05 +01:00
int max_tokens ;
2026-02-10 21:20:19 +01:00
int max_spawn_depth ;
int max_total_spawns ;
2026-01-28 19:34:39 +01:00
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 ) {
2026-01-29 06:01:05 +01:00
const char * key = getenv ( " R_KEY " ) ;
2026-01-28 19:34:39 +01:00
if ( key & & * key ) return key ;
2026-01-29 06:01:05 +01:00
key = getenv ( " OPENROUTER_API_KEY " ) ;
2026-01-28 19:34:39 +01:00
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 ;
2026-01-29 06:01:05 +01:00
const char * max_tokens_env = getenv ( " R_MAX_TOKENS " ) ;
instance - > max_tokens = max_tokens_env ? atoi ( max_tokens_env ) : 4096 ;
2026-02-10 21:20:19 +01:00
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 ;
2026-01-28 19:34:39 +01:00
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 ) ;
2026-02-14 08:07:05 +01:00
free ( instance - > current_prompt ) ;
2026-01-28 19:34:39 +01:00
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 ;
}
2026-01-29 06:01:05 +01:00
int r_config_get_max_tokens ( r_config_handle cfg ) {
return cfg ? cfg - > max_tokens : 4096 ;
}
2026-01-28 19:34:39 +01:00
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 ;
}
2026-02-10 21:20:19 +01:00
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 ;
}
2026-02-14 08:07:05 +01:00
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 ;
}
2026-02-10 21:20:19 +01:00
/*
* 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. " ;
}