diff --git a/src/llm.c b/src/llm.c index f8d638e..fe690ad 100644 --- a/src/llm.c +++ b/src/llm.c @@ -65,6 +65,20 @@ static void log_provider_payload_local(const char* payload, fclose(out); } +/* + * Provider payload logging (context.logs/) is gated behind DIDACTYL_CONTEXT_DEBUG. + * Modes: "off" (or unset) = no logging, "init" or "full" = logging enabled. + * This prevents full LLM conversation transcripts (system prompts, user messages, + * tool calls, responses) from being written to disk in production. + */ +static int provider_log_enabled(void) { + const char* mode = getenv("DIDACTYL_CONTEXT_DEBUG"); + if (!mode || mode[0] == '\0') { + return 0; + } + return strcmp(mode, "off") != 0; +} + static int url_looks_like_websocket(const char* url) { if (!url) return 0; return (strncmp(url, "ws://", 5) == 0) || (strncmp(url, "wss://", 6) == 0); @@ -134,8 +148,9 @@ static char* perform_http_request(const char* url, const char* body, int is_post char provider_log_stamp[32] = {0}; unsigned long provider_log_seq = 0; int provider_log_has_pair = 0; + const int do_provider_log = provider_log_enabled(); - if (is_post && body && body[0] != '\0') { + if (do_provider_log && is_post && body && body[0] != '\0') { if (provider_log_next_stamp_seq_local(provider_log_stamp, sizeof(provider_log_stamp), &provider_log_seq) == 0) { @@ -151,7 +166,7 @@ static char* perform_http_request(const char* url, const char* body, int is_post return NULL; } - if (resp.body && resp.body_len > 0) { + if (do_provider_log && resp.body && resp.body_len > 0) { if (!provider_log_has_pair) { if (provider_log_next_stamp_seq_local(provider_log_stamp, sizeof(provider_log_stamp),