v0.0.57 - Register triggers live from self-skill websocket events
This commit is contained in:
@@ -53,11 +53,11 @@ Skills support context modes (`inject`, `full`, `override`) and per-skill LLM fa
|
||||
|
||||
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.56
|
||||
## Current Status — v0.0.57
|
||||
|
||||
**Active build — this project is barely working. Experiment at your own risk.**
|
||||
|
||||
> Last release update: v0.0.56 — Load triggers deterministically from startup events before EOSE
|
||||
> Last release update: v0.0.57 — Register triggers live from self-skill websocket events
|
||||
|
||||
- Connects to configured relays with auto-reconnect and relay state transition logging
|
||||
- Publishes configured startup events per relay as each relay becomes connected
|
||||
|
||||
@@ -1,3 +1,46 @@
|
||||
```text
|
||||
Context Log - not seen by model
|
||||
timestamp=2026-03-09 16:30:42
|
||||
phase=llm_trigger
|
||||
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
|
||||
model=claude-opus-4.6
|
||||
context_bytes=383
|
||||
approx_tokens=95
|
||||
```
|
||||
|
||||
Triggering event JSON:
|
||||
{"created_at":1773088242,"content":"Good day everyone.","tags":[],"kind":1,"pubkey":"8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e","id":"b431825da03f7e7d608cefccd01d32fb9b0a0034d6df8d37e28f3c218dbf95d1","sig":"ba3ca4addb8a7cc008a4355544a39e469bf9f2bc94c3aa69e9021875158d60e3d9324b65c60fe4d75ca6ab12ef6bc27bbd659b2e4a3a61f8366675fda08019ad"}
|
||||
|
||||
---
|
||||
|
||||
```text
|
||||
Context Log - not seen by model
|
||||
timestamp=2026-03-09 16:30:27
|
||||
phase=direct_tool_exec
|
||||
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
|
||||
model=claude-opus-4.6
|
||||
context_bytes=683
|
||||
approx_tokens=170
|
||||
```
|
||||
|
||||
slash=/trigger_list
|
||||
result_json={"success":true,"count":1,"active":1,"triggers":[{"skill_slug":"cheerleader","filter_json":"{\"kinds\":[1],\"authors\":[\"8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e\"]}","action":"llm","enabled":true,"subscribed":true,"last_fired":0,"last_seen_created_at":0}]}
|
||||
result_markdown=- **success:** true
|
||||
- **count:** 1
|
||||
- **active:** 1
|
||||
- **triggers:**
|
||||
-
|
||||
- **skill_slug:** cheerleader
|
||||
- **filter_json:** {"kinds":[1],"authors":["8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e"]}
|
||||
- **action:** llm
|
||||
- **enabled:** true
|
||||
- **subscribed:** true
|
||||
- **last_fired:** 0
|
||||
- **last_seen_created_at:** 0
|
||||
|
||||
|
||||
---
|
||||
|
||||
```text
|
||||
Context Log - not seen by model
|
||||
timestamp=2026-03-09 16:12:06
|
||||
|
||||
@@ -262,6 +262,7 @@ int main(int argc, char** argv) {
|
||||
return 1;
|
||||
}
|
||||
agent_set_trigger_manager(&trigger_manager);
|
||||
nostr_handler_set_trigger_manager(&trigger_manager);
|
||||
|
||||
deferred_trigger_load_ctx_t deferred_trigger_ctx = {
|
||||
.trigger_manager = &trigger_manager,
|
||||
|
||||
+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 56
|
||||
#define DIDACTYL_VERSION "v0.0.56"
|
||||
#define DIDACTYL_VERSION_PATCH 57
|
||||
#define DIDACTYL_VERSION "v0.0.57"
|
||||
|
||||
// Agent metadata
|
||||
#define DIDACTYL_NAME "Didactyl"
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "../../nostr_core_lib/cjson/cJSON.h"
|
||||
#include "../../nostr_core_lib/nostr_core/nostr_core.h"
|
||||
#include "debug.h"
|
||||
#include "trigger_manager.h"
|
||||
|
||||
#define NIP17_MAX_RELAYS 32
|
||||
#define NIP17_MAX_GIFT_WRAPS 8
|
||||
@@ -51,6 +52,8 @@ static pthread_mutex_t g_self_skill_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static nostr_self_skill_eose_cb_t g_self_skill_eose_cb = NULL;
|
||||
static void* g_self_skill_eose_user_data = NULL;
|
||||
|
||||
static struct trigger_manager* g_trigger_manager = NULL;
|
||||
|
||||
static char g_seen_dm_ids[DM_DEDUP_CACHE_SIZE][65];
|
||||
static int g_seen_dm_count = 0;
|
||||
static int g_seen_dm_next = 0;
|
||||
@@ -269,6 +272,7 @@ static void upsert_kind1_note(time_t created_at, const char* content);
|
||||
static int startup_self_kind1_exists(void);
|
||||
static void load_startup_display_name(void);
|
||||
static void build_startup_kind1_content(char* out, size_t out_size, const char* fallback);
|
||||
static void register_trigger_from_self_skill_event(cJSON* event);
|
||||
static void on_self_skill_event(cJSON* event, const char* relay_url, void* user_data);
|
||||
static void dm_history_clear_locked(void);
|
||||
static void dm_history_remember(const char* peer_pubkey_hex, const char* content, int incoming, time_t created_at);
|
||||
@@ -445,6 +449,72 @@ static const char* find_tag_value_local(cJSON* tags, const char* key) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int parse_enabled_flag_local(const char* enabled_s) {
|
||||
if (!enabled_s || enabled_s[0] == '\0') {
|
||||
return 1;
|
||||
}
|
||||
return (strcmp(enabled_s, "false") == 0 || strcmp(enabled_s, "0") == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
static void register_trigger_from_self_skill_event(cJSON* event) {
|
||||
if (!event || !g_cfg || !g_trigger_manager) {
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON* kind = cJSON_GetObjectItemCaseSensitive(event, "kind");
|
||||
cJSON* pubkey = cJSON_GetObjectItemCaseSensitive(event, "pubkey");
|
||||
cJSON* content = cJSON_GetObjectItemCaseSensitive(event, "content");
|
||||
cJSON* tags = cJSON_GetObjectItemCaseSensitive(event, "tags");
|
||||
|
||||
if (!kind || !cJSON_IsNumber(kind) ||
|
||||
!pubkey || !cJSON_IsString(pubkey) || !pubkey->valuestring ||
|
||||
!content || !cJSON_IsString(content) || !content->valuestring ||
|
||||
!tags || !cJSON_IsArray(tags)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int kind_val = (int)kind->valuedouble;
|
||||
if (kind_val != 31123 && kind_val != 31124) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(pubkey->valuestring, g_cfg->keys.public_key_hex) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char* slug = find_tag_value_local(tags, "d");
|
||||
const char* trigger = find_tag_value_local(tags, "trigger");
|
||||
const char* filter = find_tag_value_local(tags, "filter");
|
||||
const char* action = find_tag_value_local(tags, "action");
|
||||
const char* enabled = find_tag_value_local(tags, "enabled");
|
||||
|
||||
if (!slug || slug[0] == '\0' ||
|
||||
!trigger || strcmp(trigger, "nostr-subscription") != 0 ||
|
||||
!filter || filter[0] == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
trigger_action_type_t action_type = (action && strcmp(action, "template") == 0)
|
||||
? TRIGGER_ACTION_TEMPLATE
|
||||
: TRIGGER_ACTION_LLM;
|
||||
int is_enabled = parse_enabled_flag_local(enabled);
|
||||
|
||||
int rc = trigger_manager_add((trigger_manager_t*)g_trigger_manager,
|
||||
slug,
|
||||
content->valuestring,
|
||||
filter,
|
||||
action_type,
|
||||
is_enabled);
|
||||
if (rc == 0) {
|
||||
DEBUG_INFO("[didactyl] live self-skill trigger registered slug=%s action=%s enabled=%d",
|
||||
slug,
|
||||
action_type == TRIGGER_ACTION_TEMPLATE ? "template" : "llm",
|
||||
is_enabled);
|
||||
} else {
|
||||
DEBUG_WARN("[didactyl] live self-skill trigger register failed slug=%s", slug);
|
||||
}
|
||||
}
|
||||
|
||||
static void self_skill_cache_upsert_event_locked(cJSON* event) {
|
||||
if (!event || !cJSON_IsObject(event)) {
|
||||
return;
|
||||
@@ -1165,6 +1235,8 @@ static void on_self_skill_event(cJSON* event, const char* relay_url, void* user_
|
||||
return;
|
||||
}
|
||||
|
||||
register_trigger_from_self_skill_event(event);
|
||||
|
||||
pthread_mutex_lock(&g_self_skill_mutex);
|
||||
self_skill_cache_upsert_event_locked(event);
|
||||
pthread_mutex_unlock(&g_self_skill_mutex);
|
||||
@@ -1333,6 +1405,10 @@ int nostr_handler_subscribe_admin_context(void) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
void nostr_handler_set_trigger_manager(struct trigger_manager* trigger_manager) {
|
||||
g_trigger_manager = trigger_manager;
|
||||
}
|
||||
|
||||
int nostr_handler_subscribe_self_skills(void) {
|
||||
if (!g_cfg || !g_pool) {
|
||||
return -1;
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "cjson/cJSON.h"
|
||||
#include "../nostr_core_lib/nostr_core/nostr_core.h"
|
||||
|
||||
struct trigger_manager;
|
||||
|
||||
typedef enum {
|
||||
DIDACTYL_SENDER_ADMIN = 1,
|
||||
DIDACTYL_SENDER_WOT = 2,
|
||||
@@ -31,6 +33,7 @@ typedef struct {
|
||||
typedef void (*nostr_self_skill_eose_cb_t)(int event_count, void* user_data);
|
||||
|
||||
int nostr_handler_init(didactyl_config_t* config);
|
||||
void nostr_handler_set_trigger_manager(struct trigger_manager* trigger_manager);
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user