v0.0.43 - Unify self-authored event cache for skills and adoption list
This commit is contained in:
@@ -51,11 +51,11 @@ Agents learn capabilities through skills — Nostr events that any agent can di
|
||||
|
||||
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.0.42
|
||||
## Current Status — v0.0.43
|
||||
|
||||
**Active build — this project is barely working. Experiment at your own risk.**
|
||||
|
||||
> Last release update: v0.0.42 — Add self-skill subscription cache and make skill_list read from cache
|
||||
> Last release update: v0.0.43 — Unify self-authored event cache for skills and adoption list
|
||||
|
||||
- Connects to configured relays with auto-reconnect and relay state transition logging
|
||||
- Publishes configured startup events per relay as each relay becomes connected
|
||||
|
||||
+57
-44
@@ -1632,25 +1632,7 @@ static int refresh_adopted_skills_cache_if_needed(void) {
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
int tmp_count = 0;
|
||||
|
||||
cJSON* adopt_filter = cJSON_CreateObject();
|
||||
cJSON* kinds = cJSON_CreateArray();
|
||||
cJSON* authors = cJSON_CreateArray();
|
||||
if (!adopt_filter || !kinds || !authors) {
|
||||
cJSON_Delete(adopt_filter);
|
||||
cJSON_Delete(kinds);
|
||||
cJSON_Delete(authors);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cJSON_AddItemToArray(kinds, cJSON_CreateNumber(10123));
|
||||
cJSON_AddItemToObject(adopt_filter, "kinds", kinds);
|
||||
cJSON_AddItemToArray(authors, cJSON_CreateString(g_cfg->keys.public_key_hex));
|
||||
cJSON_AddItemToObject(adopt_filter, "authors", authors);
|
||||
cJSON_AddNumberToObject(adopt_filter, "limit", 1);
|
||||
|
||||
char* adoption_json = nostr_handler_query_json(adopt_filter, 2000);
|
||||
cJSON_Delete(adopt_filter);
|
||||
|
||||
char* adoption_json = nostr_handler_get_self_events_by_kind_json(10123);
|
||||
cJSON* adoption_events = adoption_json ? cJSON_Parse(adoption_json) : NULL;
|
||||
free(adoption_json);
|
||||
|
||||
@@ -1680,34 +1662,65 @@ static int refresh_adopted_skills_cache_if_needed(void) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cJSON* skill_filter = cJSON_CreateObject();
|
||||
cJSON* sk_kinds = cJSON_CreateArray();
|
||||
cJSON* sk_authors = cJSON_CreateArray();
|
||||
cJSON* d_values = cJSON_CreateArray();
|
||||
if (!skill_filter || !sk_kinds || !sk_authors || !d_values) {
|
||||
cJSON* skill_events = NULL;
|
||||
if (strcmp(skill_author, g_cfg->keys.public_key_hex) == 0) {
|
||||
char* skill_json = nostr_handler_get_self_events_by_kind_json(skill_kind);
|
||||
if (skill_json) {
|
||||
cJSON* all_events = cJSON_Parse(skill_json);
|
||||
free(skill_json);
|
||||
if (all_events && cJSON_IsArray(all_events)) {
|
||||
skill_events = cJSON_CreateArray();
|
||||
if (skill_events) {
|
||||
int all_n = cJSON_GetArraySize(all_events);
|
||||
for (int ai = 0; ai < all_n; ai++) {
|
||||
cJSON* ev = cJSON_GetArrayItem(all_events, ai);
|
||||
cJSON* ev_pubkey = ev ? cJSON_GetObjectItemCaseSensitive(ev, "pubkey") : NULL;
|
||||
cJSON* ev_tags = ev ? cJSON_GetObjectItemCaseSensitive(ev, "tags") : NULL;
|
||||
cJSON* ev_d = find_tag_value_string_local(ev_tags, "d");
|
||||
if (!ev_pubkey || !cJSON_IsString(ev_pubkey) || !ev_pubkey->valuestring ||
|
||||
strcmp(ev_pubkey->valuestring, skill_author) != 0 ||
|
||||
!ev_d || !cJSON_IsString(ev_d) || !ev_d->valuestring ||
|
||||
strcmp(ev_d->valuestring, skill_slug) != 0) {
|
||||
continue;
|
||||
}
|
||||
cJSON* dup = cJSON_Duplicate(ev, 1);
|
||||
if (dup) {
|
||||
cJSON_AddItemToArray(skill_events, dup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cJSON_Delete(all_events);
|
||||
}
|
||||
} else {
|
||||
cJSON* skill_filter = cJSON_CreateObject();
|
||||
cJSON* sk_kinds = cJSON_CreateArray();
|
||||
cJSON* sk_authors = cJSON_CreateArray();
|
||||
cJSON* d_values = cJSON_CreateArray();
|
||||
if (!skill_filter || !sk_kinds || !sk_authors || !d_values) {
|
||||
cJSON_Delete(skill_filter);
|
||||
cJSON_Delete(sk_kinds);
|
||||
cJSON_Delete(sk_authors);
|
||||
cJSON_Delete(d_values);
|
||||
continue;
|
||||
}
|
||||
|
||||
cJSON_AddItemToArray(sk_kinds, cJSON_CreateNumber(skill_kind));
|
||||
cJSON_AddItemToObject(skill_filter, "kinds", sk_kinds);
|
||||
cJSON_AddItemToArray(sk_authors, cJSON_CreateString(skill_author));
|
||||
cJSON_AddItemToObject(skill_filter, "authors", sk_authors);
|
||||
cJSON_AddItemToArray(d_values, cJSON_CreateString(skill_slug));
|
||||
cJSON_AddItemToObject(skill_filter, "#d", d_values);
|
||||
cJSON_AddNumberToObject(skill_filter, "limit", 1);
|
||||
|
||||
char* skill_json = nostr_handler_query_json(skill_filter, 2000);
|
||||
cJSON_Delete(skill_filter);
|
||||
cJSON_Delete(sk_kinds);
|
||||
cJSON_Delete(sk_authors);
|
||||
cJSON_Delete(d_values);
|
||||
continue;
|
||||
if (skill_json) {
|
||||
skill_events = cJSON_Parse(skill_json);
|
||||
free(skill_json);
|
||||
}
|
||||
}
|
||||
|
||||
cJSON_AddItemToArray(sk_kinds, cJSON_CreateNumber(skill_kind));
|
||||
cJSON_AddItemToObject(skill_filter, "kinds", sk_kinds);
|
||||
cJSON_AddItemToArray(sk_authors, cJSON_CreateString(skill_author));
|
||||
cJSON_AddItemToObject(skill_filter, "authors", sk_authors);
|
||||
cJSON_AddItemToArray(d_values, cJSON_CreateString(skill_slug));
|
||||
cJSON_AddItemToObject(skill_filter, "#d", d_values);
|
||||
cJSON_AddNumberToObject(skill_filter, "limit", 1);
|
||||
|
||||
char* skill_json = nostr_handler_query_json(skill_filter, 2000);
|
||||
cJSON_Delete(skill_filter);
|
||||
if (!skill_json) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cJSON* skill_events = cJSON_Parse(skill_json);
|
||||
free(skill_json);
|
||||
if (!skill_events || !cJSON_IsArray(skill_events) || cJSON_GetArraySize(skill_events) <= 0) {
|
||||
cJSON_Delete(skill_events);
|
||||
continue;
|
||||
|
||||
+2
-2
@@ -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 0
|
||||
#define DIDACTYL_VERSION_PATCH 42
|
||||
#define DIDACTYL_VERSION "v0.0.42"
|
||||
#define DIDACTYL_VERSION_PATCH 43
|
||||
#define DIDACTYL_VERSION "v0.0.43"
|
||||
|
||||
// Agent metadata
|
||||
#define DIDACTYL_NAME "Didactyl"
|
||||
|
||||
+67
-15
@@ -401,7 +401,7 @@ static void self_skill_cache_upsert_event_locked(cJSON* event) {
|
||||
}
|
||||
|
||||
int kind_val = (int)kind->valuedouble;
|
||||
if (kind_val != 31123 && kind_val != 31124) {
|
||||
if (kind_val != 31123 && kind_val != 31124 && kind_val != 10123) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -410,7 +410,7 @@ static void self_skill_cache_upsert_event_locked(cJSON* event) {
|
||||
}
|
||||
|
||||
const char* d_tag = find_tag_value_local(tags, "d");
|
||||
if (!d_tag || d_tag[0] == '\0') {
|
||||
if ((kind_val == 31123 || kind_val == 31124) && (!d_tag || d_tag[0] == '\0')) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -440,13 +440,16 @@ static void self_skill_cache_upsert_event_locked(cJSON* event) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char* ex_d = find_tag_value_local(ex_tags, "d");
|
||||
if (!ex_d || strcmp(ex_d, d_tag) != 0) {
|
||||
int ex_kind_val = (int)ex_kind->valuedouble;
|
||||
if (ex_kind_val != kind_val || strcmp(ex_pubkey->valuestring, pubkey->valuestring) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((int)ex_kind->valuedouble != kind_val || strcmp(ex_pubkey->valuestring, pubkey->valuestring) != 0) {
|
||||
continue;
|
||||
if (kind_val == 31123 || kind_val == 31124) {
|
||||
const char* ex_d = find_tag_value_local(ex_tags, "d");
|
||||
if (!ex_d || !d_tag || strcmp(ex_d, d_tag) != 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
cJSON* ex_created_at = cJSON_GetObjectItemCaseSensitive(existing, "created_at");
|
||||
@@ -1267,6 +1270,7 @@ int nostr_handler_subscribe_self_skills(void) {
|
||||
|
||||
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));
|
||||
cJSON_AddItemToObject(filter, "authors", authors);
|
||||
@@ -1291,7 +1295,7 @@ int nostr_handler_subscribe_self_skills(void) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG_INFO("[didactyl] self-skill subscriptions active for pubkey %.16s...", g_cfg->keys.public_key_hex);
|
||||
DEBUG_INFO("[didactyl] self-event subscriptions active for pubkey %.16s...", g_cfg->keys.public_key_hex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1591,6 +1595,12 @@ static int publish_kind_event_to_relays(int kind,
|
||||
relay_count,
|
||||
sent);
|
||||
|
||||
if (sent > 0) {
|
||||
pthread_mutex_lock(&g_self_skill_mutex);
|
||||
self_skill_cache_upsert_event_locked(event);
|
||||
pthread_mutex_unlock(&g_self_skill_mutex);
|
||||
}
|
||||
|
||||
cJSON_Delete(event);
|
||||
return sent > 0 ? 0 : -1;
|
||||
}
|
||||
@@ -1782,22 +1792,64 @@ const char* nostr_handler_get_system_context(void) {
|
||||
return g_system_context;
|
||||
}
|
||||
|
||||
char* nostr_handler_get_self_skill_events_json(void) {
|
||||
cJSON* dup = NULL;
|
||||
char* nostr_handler_get_self_events_by_kind_json(int kind) {
|
||||
cJSON* out = cJSON_CreateArray();
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&g_self_skill_mutex);
|
||||
if (g_self_skill_events && cJSON_IsArray(g_self_skill_events)) {
|
||||
dup = cJSON_Duplicate(g_self_skill_events, 1);
|
||||
int n = cJSON_GetArraySize(g_self_skill_events);
|
||||
for (int i = 0; i < n; i++) {
|
||||
cJSON* ev = cJSON_GetArrayItem(g_self_skill_events, i);
|
||||
cJSON* ev_kind = ev ? cJSON_GetObjectItemCaseSensitive(ev, "kind") : NULL;
|
||||
if (!ev_kind || !cJSON_IsNumber(ev_kind) || (int)ev_kind->valuedouble != kind) {
|
||||
continue;
|
||||
}
|
||||
cJSON* dup = cJSON_Duplicate(ev, 1);
|
||||
if (dup) {
|
||||
cJSON_AddItemToArray(out, dup);
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&g_self_skill_mutex);
|
||||
|
||||
if (!dup) {
|
||||
return strdup("[]");
|
||||
char* json = cJSON_PrintUnformatted(out);
|
||||
cJSON_Delete(out);
|
||||
return json ? json : strdup("[]");
|
||||
}
|
||||
|
||||
char* nostr_handler_get_self_skill_events_json(void) {
|
||||
cJSON* out = cJSON_CreateArray();
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* out = cJSON_PrintUnformatted(dup);
|
||||
cJSON_Delete(dup);
|
||||
return out;
|
||||
pthread_mutex_lock(&g_self_skill_mutex);
|
||||
if (g_self_skill_events && cJSON_IsArray(g_self_skill_events)) {
|
||||
int n = cJSON_GetArraySize(g_self_skill_events);
|
||||
for (int i = 0; i < n; i++) {
|
||||
cJSON* ev = cJSON_GetArrayItem(g_self_skill_events, i);
|
||||
cJSON* ev_kind = ev ? cJSON_GetObjectItemCaseSensitive(ev, "kind") : NULL;
|
||||
if (!ev_kind || !cJSON_IsNumber(ev_kind)) {
|
||||
continue;
|
||||
}
|
||||
int k = (int)ev_kind->valuedouble;
|
||||
if (k != 31123 && k != 31124) {
|
||||
continue;
|
||||
}
|
||||
cJSON* dup = cJSON_Duplicate(ev, 1);
|
||||
if (dup) {
|
||||
cJSON_AddItemToArray(out, dup);
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&g_self_skill_mutex);
|
||||
|
||||
char* json = cJSON_PrintUnformatted(out);
|
||||
cJSON_Delete(out);
|
||||
return json ? json : strdup("[]");
|
||||
}
|
||||
|
||||
const char* nostr_handler_get_startup_display_name(void) {
|
||||
|
||||
@@ -30,6 +30,7 @@ typedef struct {
|
||||
int nostr_handler_init(didactyl_config_t* config);
|
||||
int nostr_handler_subscribe_admin_context(void);
|
||||
int nostr_handler_subscribe_self_skills(void);
|
||||
char* nostr_handler_get_self_events_by_kind_json(int kind);
|
||||
int nostr_handler_subscribe_dms(dm_callback_t callback, void* user_data);
|
||||
int nostr_handler_send_dm(const char* recipient_pubkey_hex, const char* message);
|
||||
int nostr_handler_send_dm_auto(const char* recipient_pubkey_hex, const char* message);
|
||||
|
||||
+1
-18
@@ -893,24 +893,7 @@ static int fetch_adoption_list_tags(tools_context_t* ctx, cJSON** out_tags, char
|
||||
*out_tags = NULL;
|
||||
*out_content = NULL;
|
||||
|
||||
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(10123));
|
||||
cJSON_AddItemToObject(filter, "kinds", kinds);
|
||||
cJSON_AddItemToArray(authors, cJSON_CreateString(ctx->cfg->keys.public_key_hex));
|
||||
cJSON_AddItemToObject(filter, "authors", authors);
|
||||
cJSON_AddNumberToObject(filter, "limit", 1);
|
||||
|
||||
char* events_json = nostr_handler_query_json(filter, 8000);
|
||||
cJSON_Delete(filter);
|
||||
char* events_json = nostr_handler_get_self_events_by_kind_json(10123);
|
||||
|
||||
cJSON* tags = cJSON_CreateArray();
|
||||
char* content = strdup("");
|
||||
|
||||
+57
-43
@@ -252,24 +252,7 @@ int trigger_manager_load_from_skills(trigger_manager_t* mgr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cJSON* adopt_filter = cJSON_CreateObject();
|
||||
cJSON* kinds = cJSON_CreateArray();
|
||||
cJSON* authors = cJSON_CreateArray();
|
||||
if (!adopt_filter || !kinds || !authors) {
|
||||
cJSON_Delete(adopt_filter);
|
||||
cJSON_Delete(kinds);
|
||||
cJSON_Delete(authors);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cJSON_AddItemToArray(kinds, cJSON_CreateNumber(10123));
|
||||
cJSON_AddItemToObject(adopt_filter, "kinds", kinds);
|
||||
cJSON_AddItemToArray(authors, cJSON_CreateString(mgr->cfg->keys.public_key_hex));
|
||||
cJSON_AddItemToObject(adopt_filter, "authors", authors);
|
||||
cJSON_AddNumberToObject(adopt_filter, "limit", 1);
|
||||
|
||||
char* adoption_json = nostr_handler_query_json(adopt_filter, 2000);
|
||||
cJSON_Delete(adopt_filter);
|
||||
char* adoption_json = nostr_handler_get_self_events_by_kind_json(10123);
|
||||
if (!adoption_json) {
|
||||
return 0;
|
||||
}
|
||||
@@ -308,34 +291,65 @@ int trigger_manager_load_from_skills(trigger_manager_t* mgr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cJSON* skill_filter = cJSON_CreateObject();
|
||||
cJSON* sk_kinds = cJSON_CreateArray();
|
||||
cJSON* sk_authors = cJSON_CreateArray();
|
||||
cJSON* d_values = cJSON_CreateArray();
|
||||
if (!skill_filter || !sk_kinds || !sk_authors || !d_values) {
|
||||
cJSON* skill_events = NULL;
|
||||
if (strcmp(pubkey, mgr->cfg->keys.public_key_hex) == 0) {
|
||||
char* skill_json = nostr_handler_get_self_events_by_kind_json(kind);
|
||||
if (skill_json) {
|
||||
cJSON* all_events = cJSON_Parse(skill_json);
|
||||
free(skill_json);
|
||||
if (all_events && cJSON_IsArray(all_events)) {
|
||||
skill_events = cJSON_CreateArray();
|
||||
if (skill_events) {
|
||||
int all_n = cJSON_GetArraySize(all_events);
|
||||
for (int ai = 0; ai < all_n; ai++) {
|
||||
cJSON* ev = cJSON_GetArrayItem(all_events, ai);
|
||||
cJSON* ev_pubkey = ev ? cJSON_GetObjectItemCaseSensitive(ev, "pubkey") : NULL;
|
||||
cJSON* ev_tags = ev ? cJSON_GetObjectItemCaseSensitive(ev, "tags") : NULL;
|
||||
cJSON* ev_d = find_tag_value_string(ev_tags, "d");
|
||||
if (!ev_pubkey || !cJSON_IsString(ev_pubkey) || !ev_pubkey->valuestring ||
|
||||
strcmp(ev_pubkey->valuestring, pubkey) != 0 ||
|
||||
!ev_d || !cJSON_IsString(ev_d) || !ev_d->valuestring ||
|
||||
strcmp(ev_d->valuestring, slug) != 0) {
|
||||
continue;
|
||||
}
|
||||
cJSON* dup = cJSON_Duplicate(ev, 1);
|
||||
if (dup) {
|
||||
cJSON_AddItemToArray(skill_events, dup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cJSON_Delete(all_events);
|
||||
}
|
||||
} else {
|
||||
cJSON* skill_filter = cJSON_CreateObject();
|
||||
cJSON* sk_kinds = cJSON_CreateArray();
|
||||
cJSON* sk_authors = cJSON_CreateArray();
|
||||
cJSON* d_values = cJSON_CreateArray();
|
||||
if (!skill_filter || !sk_kinds || !sk_authors || !d_values) {
|
||||
cJSON_Delete(skill_filter);
|
||||
cJSON_Delete(sk_kinds);
|
||||
cJSON_Delete(sk_authors);
|
||||
cJSON_Delete(d_values);
|
||||
continue;
|
||||
}
|
||||
|
||||
cJSON_AddItemToArray(sk_kinds, cJSON_CreateNumber(kind));
|
||||
cJSON_AddItemToObject(skill_filter, "kinds", sk_kinds);
|
||||
cJSON_AddItemToArray(sk_authors, cJSON_CreateString(pubkey));
|
||||
cJSON_AddItemToObject(skill_filter, "authors", sk_authors);
|
||||
cJSON_AddItemToArray(d_values, cJSON_CreateString(slug));
|
||||
cJSON_AddItemToObject(skill_filter, "#d", d_values);
|
||||
cJSON_AddNumberToObject(skill_filter, "limit", 1);
|
||||
|
||||
char* skill_json = nostr_handler_query_json(skill_filter, 2000);
|
||||
cJSON_Delete(skill_filter);
|
||||
cJSON_Delete(sk_kinds);
|
||||
cJSON_Delete(sk_authors);
|
||||
cJSON_Delete(d_values);
|
||||
continue;
|
||||
if (skill_json) {
|
||||
skill_events = cJSON_Parse(skill_json);
|
||||
free(skill_json);
|
||||
}
|
||||
}
|
||||
|
||||
cJSON_AddItemToArray(sk_kinds, cJSON_CreateNumber(kind));
|
||||
cJSON_AddItemToObject(skill_filter, "kinds", sk_kinds);
|
||||
cJSON_AddItemToArray(sk_authors, cJSON_CreateString(pubkey));
|
||||
cJSON_AddItemToObject(skill_filter, "authors", sk_authors);
|
||||
cJSON_AddItemToArray(d_values, cJSON_CreateString(slug));
|
||||
cJSON_AddItemToObject(skill_filter, "#d", d_values);
|
||||
cJSON_AddNumberToObject(skill_filter, "limit", 1);
|
||||
|
||||
char* skill_json = nostr_handler_query_json(skill_filter, 2000);
|
||||
cJSON_Delete(skill_filter);
|
||||
if (!skill_json) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cJSON* skill_events = cJSON_Parse(skill_json);
|
||||
free(skill_json);
|
||||
if (!skill_events || !cJSON_IsArray(skill_events) || cJSON_GetArraySize(skill_events) <= 0) {
|
||||
cJSON_Delete(skill_events);
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user