v0.2.32 - Made user-settings recall resilient and backfill missing didactyl admin_pubkey/dm_protocol on republish
This commit is contained in:
@@ -54,11 +54,11 @@ Skills compose by adoption-list order (`10123`) and trigger tags carry runtime e
|
||||
|
||||
Didactyl will support local inference, which is very privacy preserving. Remote inference does however have it's advantages, and in those cases Didactyl supports using Bitcoin Lightning and eCash inference providers.
|
||||
|
||||
## Current Status — v0.2.31
|
||||
## Current Status — v0.2.32
|
||||
|
||||
**Active build — this project is barely working. Experiment at your own risk.**
|
||||
|
||||
> Last release update: v0.2.31 — Added kind 10050 to genesis.jsonc
|
||||
> Last release update: v0.2.32 — Made user-settings recall resilient and backfill missing didactyl admin_pubkey/dm_protocol on republish
|
||||
|
||||
- Connects to configured relays with auto-reconnect and relay state transition logging
|
||||
- Publishes configured startup events per relay as each relay becomes connected
|
||||
|
||||
65
src/main.c
65
src/main.c
@@ -741,8 +741,13 @@ static int fetch_self_config_plaintext(const didactyl_config_t* cfg, const char*
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_recalled_user_settings(didactyl_config_t* cfg, const char* plaintext) {
|
||||
static int apply_recalled_user_settings(didactyl_config_t* cfg,
|
||||
const char* plaintext,
|
||||
int* out_backfill_needed) {
|
||||
if (!cfg || !plaintext) return -1;
|
||||
if (out_backfill_needed) {
|
||||
*out_backfill_needed = 0;
|
||||
}
|
||||
|
||||
cJSON* root = cJSON_Parse(plaintext);
|
||||
if (!root || !cJSON_IsObject(root)) {
|
||||
@@ -752,7 +757,7 @@ static int apply_recalled_user_settings(didactyl_config_t* cfg, const char* plai
|
||||
|
||||
cJSON* global_llm = cJSON_GetObjectItemCaseSensitive(root, "global_llm");
|
||||
cJSON* didactyl = cJSON_GetObjectItemCaseSensitive(root, "didactyl");
|
||||
if (!global_llm || !cJSON_IsObject(global_llm) || !didactyl || !cJSON_IsObject(didactyl)) {
|
||||
if (!global_llm || !cJSON_IsObject(global_llm)) {
|
||||
cJSON_Delete(root);
|
||||
return -1;
|
||||
}
|
||||
@@ -764,15 +769,20 @@ static int apply_recalled_user_settings(didactyl_config_t* cfg, const char* plai
|
||||
cJSON* max_tokens = cJSON_GetObjectItemCaseSensitive(global_llm, "max_tokens");
|
||||
cJSON* temperature = cJSON_GetObjectItemCaseSensitive(global_llm, "temperature");
|
||||
|
||||
cJSON* admin_pubkey = cJSON_GetObjectItemCaseSensitive(didactyl, "admin_pubkey");
|
||||
cJSON* dm_protocol = cJSON_GetObjectItemCaseSensitive(didactyl, "dm_protocol");
|
||||
cJSON* max_turns = cJSON_GetObjectItemCaseSensitive(didactyl, "max_turns");
|
||||
cJSON* admin_pubkey = NULL;
|
||||
cJSON* dm_protocol = NULL;
|
||||
cJSON* max_turns = NULL;
|
||||
if (didactyl && cJSON_IsObject(didactyl)) {
|
||||
admin_pubkey = cJSON_GetObjectItemCaseSensitive(didactyl, "admin_pubkey");
|
||||
dm_protocol = cJSON_GetObjectItemCaseSensitive(didactyl, "dm_protocol");
|
||||
max_turns = cJSON_GetObjectItemCaseSensitive(didactyl, "max_turns");
|
||||
} else if (out_backfill_needed) {
|
||||
*out_backfill_needed = 1;
|
||||
}
|
||||
|
||||
if (!api_key || !cJSON_IsString(api_key) || !api_key->valuestring || api_key->valuestring[0] == '\0' ||
|
||||
!model || !cJSON_IsString(model) || !model->valuestring || model->valuestring[0] == '\0' ||
|
||||
!base_url || !cJSON_IsString(base_url) || !base_url->valuestring || base_url->valuestring[0] == '\0' ||
|
||||
!admin_pubkey || !cJSON_IsString(admin_pubkey) || !admin_pubkey->valuestring || admin_pubkey->valuestring[0] == '\0' ||
|
||||
!dm_protocol || !cJSON_IsString(dm_protocol) || !dm_protocol->valuestring || dm_protocol->valuestring[0] == '\0') {
|
||||
!base_url || !cJSON_IsString(base_url) || !base_url->valuestring || base_url->valuestring[0] == '\0') {
|
||||
cJSON_Delete(root);
|
||||
return -1;
|
||||
}
|
||||
@@ -793,16 +803,22 @@ static int apply_recalled_user_settings(didactyl_config_t* cfg, const char* plai
|
||||
cfg->llm.temperature = temperature->valuedouble;
|
||||
}
|
||||
|
||||
{
|
||||
if (admin_pubkey && cJSON_IsString(admin_pubkey) && admin_pubkey->valuestring && admin_pubkey->valuestring[0] != '\0') {
|
||||
char decoded[65] = {0};
|
||||
if (decode_pubkey_hex_or_npub_local(admin_pubkey->valuestring, decoded) != 0) {
|
||||
cJSON_Delete(root);
|
||||
return -1;
|
||||
}
|
||||
snprintf(cfg->admin.pubkey, sizeof(cfg->admin.pubkey), "%s", decoded);
|
||||
} else if (out_backfill_needed) {
|
||||
*out_backfill_needed = 1;
|
||||
}
|
||||
|
||||
dm_protocol_from_string(dm_protocol->valuestring, cfg);
|
||||
if (dm_protocol && cJSON_IsString(dm_protocol) && dm_protocol->valuestring && dm_protocol->valuestring[0] != '\0') {
|
||||
dm_protocol_from_string(dm_protocol->valuestring, cfg);
|
||||
} else if (out_backfill_needed) {
|
||||
*out_backfill_needed = 1;
|
||||
}
|
||||
|
||||
if (max_turns && cJSON_IsNumber(max_turns)) {
|
||||
int parsed = (int)max_turns->valuedouble;
|
||||
@@ -903,10 +919,13 @@ static int persist_runtime_config_to_nostr(const didactyl_config_t* cfg, int per
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int recover_missing_runtime_config_from_nostr(didactyl_config_t* cfg) {
|
||||
static int recover_missing_runtime_config_from_nostr(didactyl_config_t* cfg, int* out_backfill_needed) {
|
||||
if (!cfg) {
|
||||
return 0;
|
||||
}
|
||||
if (out_backfill_needed) {
|
||||
*out_backfill_needed = 0;
|
||||
}
|
||||
|
||||
char* settings_plaintext = NULL;
|
||||
if (fetch_self_config_plaintext(cfg, "user-settings", &settings_plaintext) != 0 || !settings_plaintext) {
|
||||
@@ -915,14 +934,22 @@ static int recover_missing_runtime_config_from_nostr(didactyl_config_t* cfg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (apply_recalled_user_settings(cfg, settings_plaintext) != 0) {
|
||||
int backfill_needed = 0;
|
||||
if (apply_recalled_user_settings(cfg, settings_plaintext, &backfill_needed) != 0) {
|
||||
DEBUG_WARN("[didactyl] startup phase: failed to parse/decrypt recalled user-settings");
|
||||
free(settings_plaintext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(settings_plaintext);
|
||||
DEBUG_INFO("[didactyl] startup phase: recovered user-settings from Nostr");
|
||||
if (out_backfill_needed) {
|
||||
*out_backfill_needed = backfill_needed;
|
||||
}
|
||||
if (backfill_needed) {
|
||||
DEBUG_INFO("[didactyl] startup phase: recovered user-settings from Nostr (missing didactyl fields will be backfilled)");
|
||||
} else {
|
||||
DEBUG_INFO("[didactyl] startup phase: recovered user-settings from Nostr");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1203,8 +1230,13 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
startup_step_begin(2, "Recover runtime config from Nostr");
|
||||
int llm_recalled_from_nostr = recover_missing_runtime_config_from_nostr(&cfg);
|
||||
startup_step_ok(2, "Recover runtime config from Nostr", llm_recalled_from_nostr ? "user-settings recalled" : NULL);
|
||||
int user_settings_backfill_needed = 0;
|
||||
int llm_recalled_from_nostr = recover_missing_runtime_config_from_nostr(&cfg, &user_settings_backfill_needed);
|
||||
startup_step_ok(2,
|
||||
"Recover runtime config from Nostr",
|
||||
llm_recalled_from_nostr
|
||||
? (user_settings_backfill_needed ? "user-settings recalled (backfill required)" : "user-settings recalled")
|
||||
: NULL);
|
||||
|
||||
startup_step_begin(3, "Validate LLM config");
|
||||
if (!llm_config_is_complete(&cfg.llm)) {
|
||||
@@ -1266,7 +1298,8 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
if (bootstrap_mode || first_run) {
|
||||
if (persist_runtime_config_to_nostr(&cfg, llm_recalled_from_nostr ? 0 : 1) != 0) {
|
||||
if (persist_runtime_config_to_nostr(&cfg,
|
||||
(llm_recalled_from_nostr && !user_settings_backfill_needed) ? 0 : 1) != 0) {
|
||||
DEBUG_WARN("[didactyl] startup phase: failed to persist encrypted runtime config to Nostr");
|
||||
} else {
|
||||
DEBUG_INFO("[didactyl] startup phase: persisted encrypted runtime config to Nostr");
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
// Using DIDACTYL_ prefix to avoid conflicts with nostr_core_lib VERSION macros
|
||||
#define DIDACTYL_VERSION_MAJOR 0
|
||||
#define DIDACTYL_VERSION_MINOR 2
|
||||
#define DIDACTYL_VERSION_PATCH 31
|
||||
#define DIDACTYL_VERSION "v0.2.31"
|
||||
#define DIDACTYL_VERSION_PATCH 32
|
||||
#define DIDACTYL_VERSION "v0.2.32"
|
||||
|
||||
// Agent metadata
|
||||
#define DIDACTYL_NAME "Didactyl"
|
||||
|
||||
@@ -1019,7 +1019,7 @@ static int apply_recalled_user_settings_wizard(didactyl_config_t* cfg, const cha
|
||||
|
||||
cJSON* global_llm = cJSON_GetObjectItemCaseSensitive(root, "global_llm");
|
||||
cJSON* didactyl = cJSON_GetObjectItemCaseSensitive(root, "didactyl");
|
||||
if (!global_llm || !cJSON_IsObject(global_llm) || !didactyl || !cJSON_IsObject(didactyl)) {
|
||||
if (!global_llm || !cJSON_IsObject(global_llm)) {
|
||||
cJSON_Delete(root);
|
||||
return -1;
|
||||
}
|
||||
@@ -1031,15 +1031,18 @@ static int apply_recalled_user_settings_wizard(didactyl_config_t* cfg, const cha
|
||||
cJSON* max_tokens = cJSON_GetObjectItemCaseSensitive(global_llm, "max_tokens");
|
||||
cJSON* temperature = cJSON_GetObjectItemCaseSensitive(global_llm, "temperature");
|
||||
|
||||
cJSON* admin_pubkey = cJSON_GetObjectItemCaseSensitive(didactyl, "admin_pubkey");
|
||||
cJSON* dm_protocol = cJSON_GetObjectItemCaseSensitive(didactyl, "dm_protocol");
|
||||
cJSON* max_turns = cJSON_GetObjectItemCaseSensitive(didactyl, "max_turns");
|
||||
cJSON* admin_pubkey = NULL;
|
||||
cJSON* dm_protocol = NULL;
|
||||
cJSON* max_turns = NULL;
|
||||
if (didactyl && cJSON_IsObject(didactyl)) {
|
||||
admin_pubkey = cJSON_GetObjectItemCaseSensitive(didactyl, "admin_pubkey");
|
||||
dm_protocol = cJSON_GetObjectItemCaseSensitive(didactyl, "dm_protocol");
|
||||
max_turns = cJSON_GetObjectItemCaseSensitive(didactyl, "max_turns");
|
||||
}
|
||||
|
||||
if (!api_key || !cJSON_IsString(api_key) || !api_key->valuestring || api_key->valuestring[0] == '\0' ||
|
||||
!model || !cJSON_IsString(model) || !model->valuestring || model->valuestring[0] == '\0' ||
|
||||
!base_url || !cJSON_IsString(base_url) || !base_url->valuestring || base_url->valuestring[0] == '\0' ||
|
||||
!admin_pubkey || !cJSON_IsString(admin_pubkey) || !admin_pubkey->valuestring || admin_pubkey->valuestring[0] == '\0' ||
|
||||
!dm_protocol || !cJSON_IsString(dm_protocol) || !dm_protocol->valuestring || dm_protocol->valuestring[0] == '\0') {
|
||||
!base_url || !cJSON_IsString(base_url) || !base_url->valuestring || base_url->valuestring[0] == '\0') {
|
||||
cJSON_Delete(root);
|
||||
return -1;
|
||||
}
|
||||
@@ -1060,7 +1063,7 @@ static int apply_recalled_user_settings_wizard(didactyl_config_t* cfg, const cha
|
||||
cfg->llm.temperature = temperature->valuedouble;
|
||||
}
|
||||
|
||||
{
|
||||
if (admin_pubkey && cJSON_IsString(admin_pubkey) && admin_pubkey->valuestring && admin_pubkey->valuestring[0] != '\0') {
|
||||
char decoded[65] = {0};
|
||||
if (decode_pubkey_hex_or_npub_local(admin_pubkey->valuestring, decoded) != 0) {
|
||||
cJSON_Delete(root);
|
||||
@@ -1069,12 +1072,14 @@ static int apply_recalled_user_settings_wizard(didactyl_config_t* cfg, const cha
|
||||
snprintf(cfg->admin.pubkey, sizeof(cfg->admin.pubkey), "%s", decoded);
|
||||
}
|
||||
|
||||
if (strcmp(dm_protocol->valuestring, "nip17") == 0) {
|
||||
cfg->dm_protocol = DM_PROTOCOL_NIP17;
|
||||
} else if (strcmp(dm_protocol->valuestring, "both") == 0) {
|
||||
cfg->dm_protocol = DM_PROTOCOL_BOTH;
|
||||
} else {
|
||||
cfg->dm_protocol = DM_PROTOCOL_NIP04;
|
||||
if (dm_protocol && cJSON_IsString(dm_protocol) && dm_protocol->valuestring && dm_protocol->valuestring[0] != '\0') {
|
||||
if (strcmp(dm_protocol->valuestring, "nip17") == 0) {
|
||||
cfg->dm_protocol = DM_PROTOCOL_NIP17;
|
||||
} else if (strcmp(dm_protocol->valuestring, "both") == 0) {
|
||||
cfg->dm_protocol = DM_PROTOCOL_BOTH;
|
||||
} else {
|
||||
cfg->dm_protocol = DM_PROTOCOL_NIP04;
|
||||
}
|
||||
}
|
||||
|
||||
if (max_turns && cJSON_IsNumber(max_turns)) {
|
||||
|
||||
Reference in New Issue
Block a user