diff --git a/README.md b/README.md index 439f07a..4771ee7 100644 --- a/README.md +++ b/README.md @@ -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.41 +## Current Status — v0.2.42 **Active build — this project is barely working. Experiment at your own risk.** -> Last release update: v0.2.41 — Fix adopted-skills cache to select latest kind 10123 event by created_at in agent refresh path +> Last release update: v0.2.42 — Make skill_refresh re-query relays and reload self-skill cache before invalidating adopted-skills cache - Connects to configured relays with auto-reconnect and relay state transition logging - Publishes configured startup events per relay as each relay becomes connected diff --git a/src/main.h b/src/main.h index 0d5b33b..59cbfdb 100644 --- a/src/main.h +++ b/src/main.h @@ -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 41 -#define DIDACTYL_VERSION "v0.2.41" +#define DIDACTYL_VERSION_PATCH 42 +#define DIDACTYL_VERSION "v0.2.42" // Agent metadata #define DIDACTYL_NAME "Didactyl" diff --git a/src/nostr_handler.c b/src/nostr_handler.c index 090b360..113e93b 100644 --- a/src/nostr_handler.c +++ b/src/nostr_handler.c @@ -3694,6 +3694,75 @@ char* nostr_handler_get_self_skill_events_json(void) { return json ? json : strdup("[]"); } +int nostr_handler_refresh_self_skill_cache_from_relays(int timeout_ms) { + if (!g_cfg || !g_pool) { + return -1; + } + + int effective_timeout_ms = timeout_ms > 0 ? timeout_ms : 5000; + + cJSON* filter = cJSON_CreateObject(); + cJSON* kinds = cJSON_CreateArray(); + cJSON* authors = cJSON_CreateArray(); + if (!filter || !kinds || !authors) { + cJSON_Delete(filter); + cJSON_Delete(kinds); + cJSON_Delete(authors); + return -1; + } + + cJSON_AddItemToArray(kinds, cJSON_CreateNumber(31123)); + cJSON_AddItemToArray(kinds, cJSON_CreateNumber(31124)); + cJSON_AddItemToArray(kinds, cJSON_CreateNumber(10123)); + cJSON_AddItemToObject(filter, "kinds", kinds); + + cJSON_AddItemToArray(authors, cJSON_CreateString(g_cfg->keys.public_key_hex)); + if (g_cfg->admin.pubkey[0] != '\0' && strcmp(g_cfg->admin.pubkey, g_cfg->keys.public_key_hex) != 0) { + cJSON_AddItemToArray(authors, cJSON_CreateString(g_cfg->admin.pubkey)); + } + cJSON_AddItemToObject(filter, "authors", authors); + cJSON_AddNumberToObject(filter, "limit", 500); + + char* events_json = nostr_handler_query_json(filter, effective_timeout_ms); + cJSON_Delete(filter); + if (!events_json) { + return -1; + } + + cJSON* events = cJSON_Parse(events_json); + free(events_json); + if (!events || !cJSON_IsArray(events)) { + cJSON_Delete(events); + return -1; + } + + int merged = 0; + pthread_mutex_lock(&g_self_skill_mutex); + int n = cJSON_GetArraySize(events); + for (int i = 0; i < n; i++) { + cJSON* ev = cJSON_GetArrayItem(events, i); + if (!ev || !cJSON_IsObject(ev)) { + continue; + } + + cJSON* kind = cJSON_GetObjectItemCaseSensitive(ev, "kind"); + int kind_val = (kind && cJSON_IsNumber(kind)) ? (int)kind->valuedouble : -1; + if (kind_val == 31124) { + (void)normalize_private_skill_event_local(ev); + } + + self_skill_cache_upsert_event_locked(ev); + merged++; + } + pthread_mutex_unlock(&g_self_skill_mutex); + + cJSON_Delete(events); + + agent_invalidate_adopted_skills_cache(); + DEBUG_INFO("[didactyl] skill_refresh relay reload merged %d self-skill/adoption events", merged); + return 0; +} + int nostr_handler_is_event_in_self_cache(const char* event_id_hex) { if (!event_id_hex || strlen(event_id_hex) != 64U) { return 0; diff --git a/src/nostr_handler.h b/src/nostr_handler.h index 009c80b..7eb92b0 100644 --- a/src/nostr_handler.h +++ b/src/nostr_handler.h @@ -77,6 +77,7 @@ int nostr_handler_validate_self_skill_cache(int* out_skill_count, int* out_adopt void nostr_handler_refresh_relay_statuses(void); int nostr_handler_sync_relays_from_config(void); char* nostr_handler_get_self_skill_events_json(void); +int nostr_handler_refresh_self_skill_cache_from_relays(int timeout_ms); int nostr_handler_is_event_in_self_cache(const char* event_id_hex); const char* nostr_handler_get_startup_display_name(void); int nostr_handler_connected_relay_count(void); diff --git a/src/tools/tool_skill.c b/src/tools/tool_skill.c index 1ca2f43..4078eb8 100644 --- a/src/tools/tool_skill.c +++ b/src/tools/tool_skill.c @@ -2474,12 +2474,17 @@ char* execute_skill_refresh(tools_context_t* ctx, const char* args_json) { (void)args_json; if (!ctx || !ctx->cfg) return json_error_local("tool context unavailable"); + int rc = nostr_handler_refresh_self_skill_cache_from_relays(5000); + if (rc != 0) { + return json_error_local("skill_refresh failed to reload self-skill cache from relays"); + } + agent_invalidate_adopted_skills_cache(); cJSON* out = cJSON_CreateObject(); if (!out) return NULL; cJSON_AddBoolToObject(out, "success", 1); - cJSON_AddStringToObject(out, "message", "adopted skills cache invalidated; next context build will reload skills"); + cJSON_AddStringToObject(out, "message", "self-skill cache refreshed from relays; adopted skills cache invalidated; next context build will use latest relay data"); char* json = cJSON_PrintUnformatted(out); cJSON_Delete(out); return json;